vitess.io/vitess@v0.16.2/go/vt/zkctl/zkconf.go (about)

     1  //go:build !codeanalysis
     2  // +build !codeanalysis
     3  
     4  /*
     5  Copyright 2019 The Vitess Authors.
     6  
     7  Licensed under the Apache License, Version 2.0 (the "License");
     8  you may not use this file except in compliance with the License.
     9  You may obtain a copy of the License at
    10  
    11      http://www.apache.org/licenses/LICENSE-2.0
    12  
    13  Unless required by applicable law or agreed to in writing, software
    14  distributed under the License is distributed on an "AS IS" BASIS,
    15  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    16  See the License for the specific language governing permissions and
    17  limitations under the License.
    18  */
    19  
    20  /*
    21    Generate zoo.conf files from templates.
    22  */
    23  
    24  package zkctl
    25  
    26  import (
    27  	"bytes"
    28  	"fmt"
    29  	"os"
    30  	"path"
    31  	"strconv"
    32  	"strings"
    33  	"text/template"
    34  
    35  	"vitess.io/vitess/go/netutil"
    36  	"vitess.io/vitess/go/vt/env"
    37  	"vitess.io/vitess/go/vt/log"
    38  )
    39  
    40  type zkServerAddr struct {
    41  	ServerId     uint32 // nolint:revive
    42  	Hostname     string
    43  	LeaderPort   int
    44  	ElectionPort int
    45  	ClientPort   int
    46  }
    47  
    48  type ZkConfig struct {
    49  	ServerId   uint32 // nolint:revive
    50  	ClientPort int
    51  	Servers    []zkServerAddr
    52  	Global     bool
    53  }
    54  
    55  /* ServerId is a unique id for a server - must be 1-255
    56   */
    57  func NewZkConfig() *ZkConfig {
    58  	return &ZkConfig{
    59  		ClientPort: 2181,
    60  		Servers:    make([]zkServerAddr, 0, 16),
    61  	}
    62  }
    63  
    64  func (cnf *ZkConfig) DataDir() string {
    65  	baseDir := env.VtDataRoot()
    66  	if cnf.Global {
    67  		return fmt.Sprintf("%v/zk_global_%03d", baseDir, cnf.ServerId)
    68  	}
    69  	return fmt.Sprintf("%v/zk_%03d", baseDir, cnf.ServerId)
    70  }
    71  
    72  func (cnf *ZkConfig) DirectoryList() []string {
    73  	return []string{
    74  		cnf.DataDir(),
    75  		cnf.LogDir(),
    76  	}
    77  }
    78  
    79  func (cnf *ZkConfig) LogDir() string {
    80  	return path.Join(cnf.DataDir(), "logs")
    81  }
    82  
    83  func (cnf *ZkConfig) ConfigFile() string {
    84  	return path.Join(cnf.DataDir(), "zoo.cfg")
    85  }
    86  
    87  func (cnf *ZkConfig) PidFile() string {
    88  	return path.Join(cnf.DataDir(), "zk.pid")
    89  }
    90  
    91  func (cnf *ZkConfig) MyidFile() string {
    92  	return path.Join(cnf.DataDir(), "myid")
    93  }
    94  
    95  func (cnf *ZkConfig) WriteMyid() error {
    96  	return os.WriteFile(cnf.MyidFile(), []byte(fmt.Sprintf("%v", cnf.ServerId)), 0664)
    97  }
    98  
    99  /*
   100  Search for first existing file in cnfFiles and subsitute in the right values.
   101  */
   102  func MakeZooCfg(cnfFiles []string, cnf *ZkConfig, header string) (string, error) {
   103  	myTemplateSource := new(bytes.Buffer)
   104  	for _, line := range strings.Split(header, "\n") {
   105  		fmt.Fprintf(myTemplateSource, "## %v\n", strings.TrimSpace(line))
   106  	}
   107  	var dataErr error
   108  	for _, path := range cnfFiles {
   109  		data, dataErr := os.ReadFile(path)
   110  		if dataErr != nil {
   111  			continue
   112  		}
   113  		myTemplateSource.WriteString("## " + path + "\n")
   114  		myTemplateSource.Write(data)
   115  	}
   116  	if dataErr != nil {
   117  		return "", dataErr
   118  	}
   119  
   120  	myTemplate, err := template.New("foo").Parse(myTemplateSource.String())
   121  	if err != nil {
   122  		return "", err
   123  	}
   124  	cnfData := new(bytes.Buffer)
   125  	err = myTemplate.Execute(cnfData, cnf)
   126  	if err != nil {
   127  		return "", err
   128  	}
   129  	return cnfData.String(), nil
   130  }
   131  
   132  const GuessMyID = 0
   133  
   134  /*
   135  Create a config for this instance.
   136  
   137  <server_id>@<hostname>:<leader_port>:<election_port>:<client_port>
   138  
   139  If server_id > 1000, then we assume this is a global quorum.
   140  server_id's must be 1-255, global id's are 1001-1255 mod 1000.
   141  */
   142  func MakeZkConfigFromString(cmdLine string, myID uint32) *ZkConfig {
   143  	zkConfig := NewZkConfig()
   144  	for _, zki := range strings.Split(cmdLine, ",") {
   145  		zkiParts := strings.SplitN(zki, "@", 2)
   146  		if len(zkiParts) != 2 {
   147  			panic("bad command line format for zk config")
   148  		}
   149  		zkID := zkiParts[0]
   150  		zkAddrParts := strings.Split(zkiParts[1], ":")
   151  		serverId, _ := strconv.ParseUint(zkID, 10, 0) // nolint:revive
   152  		if serverId > 1000 {
   153  			serverId = serverId % 1000
   154  			zkConfig.Global = true
   155  		}
   156  		myID = myID % 1000
   157  
   158  		zkServer := zkServerAddr{ServerId: uint32(serverId), ClientPort: 2181,
   159  			LeaderPort: 2888, ElectionPort: 3888}
   160  		switch len(zkAddrParts) {
   161  		case 4:
   162  			zkServer.ClientPort, _ = strconv.Atoi(zkAddrParts[3])
   163  			fallthrough
   164  		case 3:
   165  			zkServer.ElectionPort, _ = strconv.Atoi(zkAddrParts[2])
   166  			fallthrough
   167  		case 2:
   168  			zkServer.LeaderPort, _ = strconv.Atoi(zkAddrParts[1])
   169  			fallthrough
   170  		case 1:
   171  			zkServer.Hostname = zkAddrParts[0]
   172  			// if !strings.Contains(zkServer.Hostname, ".") {
   173  			// 	panic(fmt.Errorf("expected fully qualified hostname: %v", zkServer.Hostname))
   174  			// }
   175  		default:
   176  			panic(fmt.Errorf("bad command line format for zk config"))
   177  		}
   178  		zkConfig.Servers = append(zkConfig.Servers, zkServer)
   179  	}
   180  	hostname := netutil.FullyQualifiedHostnameOrPanic()
   181  	log.Infof("Fully qualified machine hostname was detected as: %v", hostname)
   182  	for _, zkServer := range zkConfig.Servers {
   183  		if (myID > 0 && myID == zkServer.ServerId) || (myID == 0 && zkServer.Hostname == hostname) {
   184  			zkConfig.ServerId = zkServer.ServerId
   185  			zkConfig.ClientPort = zkServer.ClientPort
   186  			break
   187  		}
   188  	}
   189  	if zkConfig.ServerId == 0 {
   190  		panic(fmt.Errorf("no zk server found for host %v in config %v", hostname, cmdLine))
   191  	}
   192  	return zkConfig
   193  }