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 }