github.com/pingcap/tiup@v1.15.1/components/playground/instance/pump.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 instance
    15  
    16  import (
    17  	"context"
    18  	"fmt"
    19  	"net/http"
    20  	"path/filepath"
    21  	"strings"
    22  	"time"
    23  
    24  	tiupexec "github.com/pingcap/tiup/pkg/exec"
    25  	"github.com/pingcap/tiup/pkg/utils"
    26  )
    27  
    28  // Pump represent a pump instance.
    29  type Pump struct {
    30  	instance
    31  	pds []*PDInstance
    32  	Process
    33  }
    34  
    35  var _ Instance = &Pump{}
    36  
    37  // NewPump create a Pump instance.
    38  func NewPump(binPath string, dir, host, configPath string, id int, pds []*PDInstance) *Pump {
    39  	pump := &Pump{
    40  		instance: instance{
    41  			BinPath:    binPath,
    42  			ID:         id,
    43  			Dir:        dir,
    44  			Host:       host,
    45  			Port:       utils.MustGetFreePort(host, 8249),
    46  			ConfigPath: configPath,
    47  		},
    48  		pds: pds,
    49  	}
    50  	pump.StatusPort = pump.Port
    51  	return pump
    52  }
    53  
    54  // NodeID return the node id of pump.
    55  func (p *Pump) NodeID() string {
    56  	return fmt.Sprintf("pump_%d", p.ID)
    57  }
    58  
    59  // Ready return nil when pump is ready to serve.
    60  func (p *Pump) Ready(ctx context.Context) error {
    61  	url := fmt.Sprintf("http://%s/status", utils.JoinHostPort(p.Host, p.Port))
    62  
    63  	ready := func() bool {
    64  		resp, err := http.Get(url)
    65  		if err != nil {
    66  			return false
    67  		}
    68  		defer resp.Body.Close()
    69  		return resp.StatusCode == 200
    70  	}
    71  
    72  	for {
    73  		if ready() {
    74  			return nil
    75  		}
    76  
    77  		select {
    78  		case <-ctx.Done():
    79  			return ctx.Err()
    80  		case <-time.After(time.Second):
    81  			// just retry
    82  		}
    83  	}
    84  }
    85  
    86  // Addr return the address of Pump.
    87  func (p *Pump) Addr() string {
    88  	return utils.JoinHostPort(AdvertiseHost(p.Host), p.Port)
    89  }
    90  
    91  // Start implements Instance interface.
    92  func (p *Pump) Start(ctx context.Context, version utils.Version) error {
    93  	endpoints := pdEndpoints(p.pds, true)
    94  
    95  	args := []string{
    96  		fmt.Sprintf("--node-id=%s", p.NodeID()),
    97  		fmt.Sprintf("--addr=%s", utils.JoinHostPort(p.Host, p.Port)),
    98  		fmt.Sprintf("--advertise-addr=%s", utils.JoinHostPort(AdvertiseHost(p.Host), p.Port)),
    99  		fmt.Sprintf("--pd-urls=%s", strings.Join(endpoints, ",")),
   100  		fmt.Sprintf("--log-file=%s", p.LogFile()),
   101  	}
   102  	if p.ConfigPath != "" {
   103  		args = append(args, fmt.Sprintf("--config=%s", p.ConfigPath))
   104  	}
   105  
   106  	var err error
   107  	if p.BinPath, err = tiupexec.PrepareBinary("pump", version, p.BinPath); err != nil {
   108  		return err
   109  	}
   110  	p.Process = &process{cmd: PrepareCommand(ctx, p.BinPath, args, nil, p.Dir)}
   111  
   112  	logIfErr(p.Process.SetOutputFile(p.LogFile()))
   113  	return p.Process.Start()
   114  }
   115  
   116  // Component return component name.
   117  func (p *Pump) Component() string {
   118  	return "pump"
   119  }
   120  
   121  // LogFile return the log file.
   122  func (p *Pump) LogFile() string {
   123  	return filepath.Join(p.Dir, "pump.log")
   124  }