github.com/pingcap/tiup@v1.15.1/components/playground/instance/pd.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  	"path/filepath"
    20  	"strings"
    21  
    22  	"github.com/pingcap/errors"
    23  	tiupexec "github.com/pingcap/tiup/pkg/exec"
    24  	"github.com/pingcap/tiup/pkg/utils"
    25  )
    26  
    27  // PDRole is the role of PD.
    28  type PDRole string
    29  
    30  const (
    31  	// PDRoleNormal is the default role of PD
    32  	PDRoleNormal PDRole = "pd"
    33  	// PDRoleAPI is the role of PD API
    34  	PDRoleAPI PDRole = "api"
    35  	// PDRoleTSO is the role of PD TSO
    36  	PDRoleTSO PDRole = "tso"
    37  	// PDRoleScheduling is the role of PD scheduling
    38  	PDRoleScheduling PDRole = "scheduling"
    39  )
    40  
    41  // PDInstance represent a running pd-server
    42  type PDInstance struct {
    43  	instance
    44  	Role          PDRole
    45  	initEndpoints []*PDInstance
    46  	joinEndpoints []*PDInstance
    47  	pds           []*PDInstance
    48  	Process
    49  	isCSEMode bool
    50  }
    51  
    52  // NewPDInstance return a PDInstance
    53  func NewPDInstance(role PDRole, binPath, dir, host, configPath string, id int, pds []*PDInstance, port int, isCSEMode bool) *PDInstance {
    54  	if port <= 0 {
    55  		port = 2379
    56  	}
    57  	return &PDInstance{
    58  		instance: instance{
    59  			BinPath:    binPath,
    60  			ID:         id,
    61  			Dir:        dir,
    62  			Host:       host,
    63  			Port:       utils.MustGetFreePort(host, 2380),
    64  			StatusPort: utils.MustGetFreePort(host, port),
    65  			ConfigPath: configPath,
    66  		},
    67  		Role:      role,
    68  		pds:       pds,
    69  		isCSEMode: isCSEMode,
    70  	}
    71  }
    72  
    73  // Join set endpoints field of PDInstance
    74  func (inst *PDInstance) Join(pds []*PDInstance) *PDInstance {
    75  	inst.joinEndpoints = pds
    76  	return inst
    77  }
    78  
    79  // InitCluster set the init cluster instance.
    80  func (inst *PDInstance) InitCluster(pds []*PDInstance) *PDInstance {
    81  	inst.initEndpoints = pds
    82  	return inst
    83  }
    84  
    85  // Name return the name of pd.
    86  func (inst *PDInstance) Name() string {
    87  	return fmt.Sprintf("pd-%d", inst.ID)
    88  }
    89  
    90  // Start calls set inst.cmd and Start
    91  func (inst *PDInstance) Start(ctx context.Context, version utils.Version) error {
    92  	configPath := filepath.Join(inst.Dir, "pd.toml")
    93  	if err := prepareConfig(
    94  		configPath,
    95  		inst.ConfigPath,
    96  		inst.getConfig(),
    97  	); err != nil {
    98  		return err
    99  	}
   100  
   101  	uid := inst.Name()
   102  	var args []string
   103  	switch inst.Role {
   104  	case PDRoleNormal, PDRoleAPI:
   105  		if inst.Role == PDRoleAPI {
   106  			args = []string{"services", "api"}
   107  		}
   108  		args = append(args, []string{
   109  			"--name=" + uid,
   110  			fmt.Sprintf("--config=%s", configPath),
   111  			fmt.Sprintf("--data-dir=%s", filepath.Join(inst.Dir, "data")),
   112  			fmt.Sprintf("--peer-urls=http://%s", utils.JoinHostPort(inst.Host, inst.Port)),
   113  			fmt.Sprintf("--advertise-peer-urls=http://%s", utils.JoinHostPort(AdvertiseHost(inst.Host), inst.Port)),
   114  			fmt.Sprintf("--client-urls=http://%s", utils.JoinHostPort(inst.Host, inst.StatusPort)),
   115  			fmt.Sprintf("--advertise-client-urls=http://%s", utils.JoinHostPort(AdvertiseHost(inst.Host), inst.StatusPort)),
   116  			fmt.Sprintf("--log-file=%s", inst.LogFile()),
   117  			fmt.Sprintf("--config=%s", configPath),
   118  		}...)
   119  		switch {
   120  		case len(inst.initEndpoints) > 0:
   121  			endpoints := make([]string, 0)
   122  			for _, pd := range inst.initEndpoints {
   123  				uid := fmt.Sprintf("pd-%d", pd.ID)
   124  				endpoints = append(endpoints, fmt.Sprintf("%s=http://%s", uid, utils.JoinHostPort(AdvertiseHost(inst.Host), pd.Port)))
   125  			}
   126  			args = append(args, fmt.Sprintf("--initial-cluster=%s", strings.Join(endpoints, ",")))
   127  		case len(inst.joinEndpoints) > 0:
   128  			endpoints := make([]string, 0)
   129  			for _, pd := range inst.joinEndpoints {
   130  				endpoints = append(endpoints, fmt.Sprintf("http://%s", utils.JoinHostPort(AdvertiseHost(inst.Host), pd.Port)))
   131  			}
   132  			args = append(args, fmt.Sprintf("--join=%s", strings.Join(endpoints, ",")))
   133  		default:
   134  			return errors.Errorf("must set the init or join instances")
   135  		}
   136  	case PDRoleTSO:
   137  		endpoints := pdEndpoints(inst.pds, true)
   138  		args = []string{
   139  			"services",
   140  			"tso",
   141  			fmt.Sprintf("--listen-addr=http://%s", utils.JoinHostPort(inst.Host, inst.StatusPort)),
   142  			fmt.Sprintf("--advertise-listen-addr=http://%s", utils.JoinHostPort(AdvertiseHost(inst.Host), inst.StatusPort)),
   143  			fmt.Sprintf("--backend-endpoints=%s", strings.Join(endpoints, ",")),
   144  			fmt.Sprintf("--log-file=%s", inst.LogFile()),
   145  			fmt.Sprintf("--config=%s", configPath),
   146  		}
   147  	case PDRoleScheduling:
   148  		endpoints := pdEndpoints(inst.pds, true)
   149  		args = []string{
   150  			"services",
   151  			"scheduling",
   152  			fmt.Sprintf("--listen-addr=http://%s", utils.JoinHostPort(inst.Host, inst.StatusPort)),
   153  			fmt.Sprintf("--advertise-listen-addr=http://%s", utils.JoinHostPort(AdvertiseHost(inst.Host), inst.StatusPort)),
   154  			fmt.Sprintf("--backend-endpoints=%s", strings.Join(endpoints, ",")),
   155  			fmt.Sprintf("--log-file=%s", inst.LogFile()),
   156  			fmt.Sprintf("--config=%s", configPath),
   157  		}
   158  	}
   159  
   160  	var err error
   161  	if inst.BinPath, err = tiupexec.PrepareBinary("pd", version, inst.BinPath); err != nil {
   162  		return err
   163  	}
   164  	inst.Process = &process{cmd: PrepareCommand(ctx, inst.BinPath, args, nil, inst.Dir)}
   165  
   166  	logIfErr(inst.Process.SetOutputFile(inst.LogFile()))
   167  	return inst.Process.Start()
   168  }
   169  
   170  // Component return the component name.
   171  func (inst *PDInstance) Component() string {
   172  	if inst.Role == PDRoleNormal || inst.Role == PDRoleAPI {
   173  		return "pd"
   174  	}
   175  	return string(inst.Role)
   176  }
   177  
   178  // LogFile return the log file.
   179  func (inst *PDInstance) LogFile() string {
   180  	if inst.Role == PDRoleNormal || inst.Role == PDRoleAPI {
   181  		return filepath.Join(inst.Dir, "pd.log")
   182  	}
   183  	return filepath.Join(inst.Dir, fmt.Sprintf("%s.log", string(inst.Role)))
   184  }
   185  
   186  // Addr return the listen address of PD
   187  func (inst *PDInstance) Addr() string {
   188  	return utils.JoinHostPort(AdvertiseHost(inst.Host), inst.StatusPort)
   189  }