github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/tests/mq_protocol_tests/framework/avro/kafka_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 avro
    15  
    16  import (
    17  	"encoding/json"
    18  	"io"
    19  	"net/http"
    20  	"path"
    21  
    22  	"github.com/integralist/go-findroot/find"
    23  	"github.com/pingcap/errors"
    24  	"github.com/pingcap/log"
    25  	"github.com/pingcap/tiflow/tests/mq_protocol_tests/framework"
    26  	"go.uber.org/zap"
    27  )
    28  
    29  const (
    30  	kafkaURI              = "http://127.0.0.1:18083/"
    31  	dockerComposeFilePath = framework.DockerComposeFilePathPrefix + "docker-compose-avro.yml"
    32  )
    33  
    34  // KafkaDockerEnv represents the docker-compose service defined in docker-compose-avro.yml
    35  type KafkaDockerEnv struct {
    36  	framework.DockerEnv
    37  }
    38  
    39  // NewKafkaDockerEnv creates a new KafkaDockerEnv
    40  func NewKafkaDockerEnv(dockerComposeFile string) *KafkaDockerEnv {
    41  	healthChecker := func() error {
    42  		resp, err := http.Get(kafkaURI)
    43  		if err != nil {
    44  			return err
    45  		}
    46  
    47  		if resp.Body == nil {
    48  			return errors.New("kafka Connect HealthCheck returns empty body")
    49  		}
    50  		defer func() { _ = resp.Body.Close() }()
    51  
    52  		bytes, err := io.ReadAll(resp.Body)
    53  		if err != nil {
    54  			return err
    55  		}
    56  
    57  		m := make(map[string]interface{})
    58  		err = json.Unmarshal(bytes, &m)
    59  		if err != nil {
    60  			return err
    61  		}
    62  
    63  		healthy, ok := m["healthy"]
    64  		if !ok {
    65  			return errors.New("kafka connect healthcheck did not return health info")
    66  		}
    67  
    68  		if v, ok := healthy.(bool); !ok || !v {
    69  			return errors.Errorf("kafka connect not healthy: %v", m)
    70  		}
    71  
    72  		// Also check cdc cluster.
    73  		return framework.CdcHealthCheck(framework.ControllerContainerName, framework.UpstreamPD)
    74  	}
    75  
    76  	var file string
    77  	if dockerComposeFile == "" {
    78  		st, err := find.Repo()
    79  		if err != nil {
    80  			log.Fatal("Could not find git repo root", zap.Error(err))
    81  		}
    82  		file = path.Join(st.Path, dockerComposeFilePath)
    83  	} else {
    84  		file = dockerComposeFile
    85  	}
    86  
    87  	return &KafkaDockerEnv{DockerEnv: framework.DockerEnv{
    88  		DockerComposeOperator: framework.DockerComposeOperator{
    89  			FileName:      file,
    90  			Controller:    framework.ControllerContainerName,
    91  			HealthChecker: healthChecker,
    92  		},
    93  	}}
    94  }
    95  
    96  // Setup brings up a docker-compose service
    97  func (d *KafkaDockerEnv) Setup() {
    98  	d.DockerEnv.Setup()
    99  	if err := createConnector(); err != nil {
   100  		log.Fatal("failed to create connector", zap.Error(err))
   101  	}
   102  }
   103  
   104  // Reset implements Environment
   105  func (d *KafkaDockerEnv) Reset() {
   106  	d.DockerEnv.Reset()
   107  	if err := d.resetSchemaRegistry(); err != nil {
   108  		log.Fatal("failed to reset schema registry", zap.Error(err))
   109  	}
   110  	if err := d.resetKafkaConnector(); err != nil {
   111  		log.Fatal("failed to reset kafka connector", zap.Error(err))
   112  	}
   113  }
   114  
   115  func (d *KafkaDockerEnv) resetSchemaRegistry() error {
   116  	subjectsURL := "http://127.0.0.1:8081/subjects/"
   117  	resp, err := http.Get(subjectsURL)
   118  	if err != nil {
   119  		return err
   120  	}
   121  	if resp.Body == nil {
   122  		return errors.New("get schema registry subjects returns empty body")
   123  	}
   124  	defer resp.Body.Close()
   125  
   126  	bytes, err := io.ReadAll(resp.Body)
   127  	if err != nil {
   128  		return err
   129  	}
   130  
   131  	subs := []string{}
   132  	err = json.Unmarshal(bytes, &subs)
   133  	if err != nil {
   134  		return err
   135  	}
   136  	for _, sub := range subs {
   137  		url := subjectsURL + sub
   138  		req, err := http.NewRequest(http.MethodDelete, url, nil)
   139  		if err != nil {
   140  			return err
   141  		}
   142  		res, err := http.DefaultClient.Do(req)
   143  		if err != nil {
   144  			return err
   145  		}
   146  		defer res.Body.Close()
   147  	}
   148  	log.Info("Deleted the schema registry subjects", zap.Any("subjects", subs))
   149  	return nil
   150  }
   151  
   152  func (d *KafkaDockerEnv) resetKafkaConnector() error {
   153  	url := "http://127.0.0.1:8083/connectors/jdbc-sink-connector-debug/"
   154  	req, err := http.NewRequest(http.MethodDelete, url, nil)
   155  	if err != nil {
   156  		return err
   157  	}
   158  	res, err := http.DefaultClient.Do(req)
   159  	if err != nil {
   160  		return err
   161  	}
   162  	defer res.Body.Close()
   163  	return createConnector()
   164  }