vitess.io/vitess@v0.16.2/go/cmd/vtgate/vtgate.go (about)

     1  /*
     2  Copyright 2019 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package main
    18  
    19  import (
    20  	"context"
    21  	"math/rand"
    22  	"strings"
    23  	"time"
    24  
    25  	"github.com/spf13/pflag"
    26  
    27  	"vitess.io/vitess/go/acl"
    28  	"vitess.io/vitess/go/exit"
    29  	"vitess.io/vitess/go/vt/discovery"
    30  	"vitess.io/vitess/go/vt/log"
    31  	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
    32  	"vitess.io/vitess/go/vt/proto/vtrpc"
    33  	"vitess.io/vitess/go/vt/servenv"
    34  	"vitess.io/vitess/go/vt/srvtopo"
    35  	"vitess.io/vitess/go/vt/topo"
    36  	"vitess.io/vitess/go/vt/topo/topoproto"
    37  	"vitess.io/vitess/go/vt/vterrors"
    38  	"vitess.io/vitess/go/vt/vtgate"
    39  	"vitess.io/vitess/go/vt/vtgate/planbuilder/plancontext"
    40  )
    41  
    42  var (
    43  	cell              = ""
    44  	tabletTypesToWait []topodatapb.TabletType
    45  	plannerName       string
    46  )
    47  
    48  func registerFlags(fs *pflag.FlagSet) {
    49  	fs.StringVar(&cell, "cell", cell, "cell to use")
    50  	fs.Var((*topoproto.TabletTypeListFlag)(&tabletTypesToWait), "tablet_types_to_wait", "Wait till connected for specified tablet types during Gateway initialization. Should be provided as a comma-separated set of tablet types.")
    51  	fs.StringVar(&plannerName, "planner-version", plannerName, "Sets the default planner to use when the session has not changed it. Valid values are: V3, Gen4, Gen4Greedy and Gen4Fallback. Gen4Fallback tries the gen4 planner and falls back to the V3 planner if the gen4 fails.")
    52  
    53  	acl.RegisterFlags(fs)
    54  }
    55  
    56  var resilientServer *srvtopo.ResilientServer
    57  
    58  func init() {
    59  	rand.Seed(time.Now().UnixNano())
    60  	servenv.RegisterDefaultFlags()
    61  	servenv.RegisterFlags()
    62  	servenv.RegisterGRPCServerFlags()
    63  	servenv.RegisterGRPCServerAuthFlags()
    64  	servenv.RegisterServiceMapFlag()
    65  	servenv.OnParse(registerFlags)
    66  }
    67  
    68  // CheckCellFlags will check validation of cell and cells_to_watch flag
    69  // it will help to avoid strange behaviors when vtgate runs but actually does not work
    70  func CheckCellFlags(ctx context.Context, serv srvtopo.Server, cell string, cellsToWatch string) error {
    71  	// topo check
    72  	var topoServer *topo.Server
    73  	if serv != nil {
    74  		var err error
    75  		topoServer, err = serv.GetTopoServer()
    76  		if err != nil {
    77  			log.Exitf("Unable to create gateway: %v", err)
    78  		}
    79  	} else {
    80  		log.Exitf("topo server cannot be nil")
    81  	}
    82  	cellsInTopo, err := topoServer.GetKnownCells(ctx)
    83  	if err != nil {
    84  		return err
    85  	}
    86  	if len(cellsInTopo) == 0 {
    87  		return vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "topo server should have at least one cell")
    88  	}
    89  
    90  	// cell valid check
    91  	if cell == "" {
    92  		return vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "cell flag must be set")
    93  	}
    94  	hasCell := false
    95  	for _, v := range cellsInTopo {
    96  		if v == cell {
    97  			hasCell = true
    98  			break
    99  		}
   100  	}
   101  	if !hasCell {
   102  		return vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "cell:[%v] does not exist in topo", cell)
   103  	}
   104  
   105  	// cells_to_watch valid check
   106  	cells := make([]string, 0, 1)
   107  	for _, c := range strings.Split(cellsToWatch, ",") {
   108  		if c == "" {
   109  			continue
   110  		}
   111  		// cell should contained in cellsInTopo
   112  		if exists := topo.InCellList(c, cellsInTopo); !exists {
   113  			return vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "cell: [%v] is not valid. Available cells: [%v]", c, strings.Join(cellsInTopo, ","))
   114  		}
   115  		cells = append(cells, c)
   116  	}
   117  	if len(cells) == 0 {
   118  		return vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "cells_to_watch flag cannot be empty")
   119  	}
   120  
   121  	return nil
   122  }
   123  
   124  func main() {
   125  	defer exit.Recover()
   126  
   127  	servenv.ParseFlags("vtgate")
   128  	servenv.Init()
   129  
   130  	ts := topo.Open()
   131  	defer ts.Close()
   132  
   133  	resilientServer = srvtopo.NewResilientServer(ts, "ResilientSrvTopoServer")
   134  
   135  	tabletTypes := make([]topodatapb.TabletType, 0, 1)
   136  	if len(tabletTypesToWait) != 0 {
   137  		for _, tt := range tabletTypesToWait {
   138  			if topoproto.IsServingType(tt) {
   139  				tabletTypes = append(tabletTypes, tt)
   140  			}
   141  		}
   142  	} else {
   143  		log.Exitf("tablet_types_to_wait flag must be set")
   144  	}
   145  
   146  	if len(tabletTypes) == 0 {
   147  		log.Exitf("tablet_types_to_wait should contain at least one serving tablet type")
   148  	}
   149  
   150  	err := CheckCellFlags(context.Background(), resilientServer, cell, vtgate.CellsToWatch)
   151  	if err != nil {
   152  		log.Exitf("cells_to_watch validation failed: %v", err)
   153  	}
   154  
   155  	plannerVersion, _ := plancontext.PlannerNameToVersion(plannerName)
   156  
   157  	// pass nil for HealthCheck and it will be created
   158  	vtg := vtgate.Init(context.Background(), nil, resilientServer, cell, tabletTypes, plannerVersion)
   159  
   160  	servenv.OnRun(func() {
   161  		// Flags are parsed now. Parse the template using the actual flag value and overwrite the current template.
   162  		discovery.ParseTabletURLTemplateFromFlag()
   163  		addStatusParts(vtg)
   164  	})
   165  	servenv.OnClose(func() {
   166  		_ = vtg.Gateway().Close(context.Background())
   167  	})
   168  	servenv.RunDefault()
   169  }