vitess.io/vitess@v0.16.2/go/cmd/vttablet/vttablet.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 // vt tablet server: Serves queries and performs housekeeping jobs. 18 package main 19 20 import ( 21 "bytes" 22 "context" 23 "os" 24 "time" 25 26 "github.com/spf13/pflag" 27 28 "vitess.io/vitess/go/acl" 29 "vitess.io/vitess/go/vt/binlog" 30 "vitess.io/vitess/go/vt/dbconfigs" 31 "vitess.io/vitess/go/vt/log" 32 "vitess.io/vitess/go/vt/mysqlctl" 33 "vitess.io/vitess/go/vt/servenv" 34 "vitess.io/vitess/go/vt/tableacl" 35 "vitess.io/vitess/go/vt/tableacl/simpleacl" 36 "vitess.io/vitess/go/vt/topo" 37 "vitess.io/vitess/go/vt/topo/topoproto" 38 "vitess.io/vitess/go/vt/vttablet/onlineddl" 39 "vitess.io/vitess/go/vt/vttablet/tabletmanager" 40 "vitess.io/vitess/go/vt/vttablet/tabletmanager/vdiff" 41 "vitess.io/vitess/go/vt/vttablet/tabletmanager/vreplication" 42 "vitess.io/vitess/go/vt/vttablet/tabletserver" 43 "vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv" 44 "vitess.io/vitess/go/yaml2" 45 "vitess.io/vitess/resources" 46 47 topodatapb "vitess.io/vitess/go/vt/proto/topodata" 48 ) 49 50 var ( 51 enforceTableACLConfig bool 52 tableACLConfig string 53 tableACLConfigReloadInterval time.Duration 54 tabletPath string 55 tabletConfig string 56 57 tm *tabletmanager.TabletManager 58 ) 59 60 func registerFlags(fs *pflag.FlagSet) { 61 fs.BoolVar(&enforceTableACLConfig, "enforce-tableacl-config", enforceTableACLConfig, "if this flag is true, vttablet will fail to start if a valid tableacl config does not exist") 62 fs.StringVar(&tableACLConfig, "table-acl-config", tableACLConfig, "path to table access checker config file; send SIGHUP to reload this file") 63 fs.DurationVar(&tableACLConfigReloadInterval, "table-acl-config-reload-interval", tableACLConfigReloadInterval, "Ticker to reload ACLs. Duration flag, format e.g.: 30s. Default: do not reload") 64 fs.StringVar(&tabletPath, "tablet-path", tabletPath, "tablet alias") 65 fs.StringVar(&tabletConfig, "tablet_config", tabletConfig, "YAML file config for tablet") 66 67 acl.RegisterFlags(fs) 68 } 69 70 func init() { 71 servenv.RegisterDefaultFlags() 72 servenv.RegisterFlags() 73 servenv.RegisterGRPCServerFlags() 74 servenv.RegisterGRPCServerAuthFlags() 75 servenv.RegisterServiceMapFlag() 76 servenv.OnParseFor("vttablet", registerFlags) 77 } 78 79 func main() { 80 dbconfigs.RegisterFlags(dbconfigs.All...) 81 mysqlctl.RegisterFlags() 82 83 servenv.ParseFlags("vttablet") 84 servenv.Init() 85 86 if tabletPath == "" { 87 log.Exit("--tablet-path required") 88 } 89 tabletAlias, err := topoproto.ParseTabletAlias(tabletPath) 90 if err != nil { 91 log.Exitf("failed to parse --tablet-path: %v", err) 92 } 93 94 // config and mycnf initializations are intertwined. 95 config, mycnf := initConfig(tabletAlias) 96 97 ts := topo.Open() 98 qsc := createTabletServer(config, ts, tabletAlias) 99 100 mysqld := mysqlctl.NewMysqld(config.DB) 101 servenv.OnClose(mysqld.Close) 102 103 if err := extractOnlineDDL(); err != nil { 104 log.Exitf("failed to extract online DDL binaries: %v", err) 105 } 106 107 // Initialize and start tm. 108 gRPCPort := int32(0) 109 if servenv.GRPCPort() != 0 { 110 gRPCPort = int32(servenv.GRPCPort()) 111 } 112 tablet, err := tabletmanager.BuildTabletFromInput(tabletAlias, int32(servenv.Port()), gRPCPort, mysqld.GetVersionString(), config.DB) 113 if err != nil { 114 log.Exitf("failed to parse --tablet-path: %v", err) 115 } 116 tm = &tabletmanager.TabletManager{ 117 BatchCtx: context.Background(), 118 TopoServer: ts, 119 Cnf: mycnf, 120 MysqlDaemon: mysqld, 121 DBConfigs: config.DB.Clone(), 122 QueryServiceControl: qsc, 123 UpdateStream: binlog.NewUpdateStream(ts, tablet.Keyspace, tabletAlias.Cell, qsc.SchemaEngine()), 124 VREngine: vreplication.NewEngine(config, ts, tabletAlias.Cell, mysqld, qsc.LagThrottler()), 125 VDiffEngine: vdiff.NewEngine(config, ts, tablet), 126 } 127 if err := tm.Start(tablet, config.Healthcheck.IntervalSeconds.Get()); err != nil { 128 log.Exitf("failed to parse --tablet-path or initialize DB credentials: %v", err) 129 } 130 servenv.OnClose(func() { 131 // Close the tm so that our topo entry gets pruned properly and any 132 // background goroutines that use the topo connection are stopped. 133 tm.Close() 134 135 // tm uses ts. So, it should be closed after tm. 136 ts.Close() 137 }) 138 139 servenv.RunDefault() 140 } 141 142 func initConfig(tabletAlias *topodatapb.TabletAlias) (*tabletenv.TabletConfig, *mysqlctl.Mycnf) { 143 tabletenv.Init() 144 // Load current config after tabletenv.Init, because it changes it. 145 config := tabletenv.NewCurrentConfig() 146 if err := config.Verify(); err != nil { 147 log.Exitf("invalid config: %v", err) 148 } 149 150 if tabletConfig != "" { 151 bytes, err := os.ReadFile(tabletConfig) 152 if err != nil { 153 log.Exitf("error reading config file %s: %v", tabletConfig, err) 154 } 155 if err := yaml2.Unmarshal(bytes, config); err != nil { 156 log.Exitf("error parsing config file %s: %v", bytes, err) 157 } 158 } 159 gotBytes, _ := yaml2.Marshal(config) 160 log.Infof("Loaded config file %s successfully:\n%s", tabletConfig, gotBytes) 161 162 var mycnf *mysqlctl.Mycnf 163 var socketFile string 164 // If no connection parameters were specified, load the mycnf file 165 // and use the socket from it. If connection parameters were specified, 166 // we assume that the mysql is not local, and we skip loading mycnf. 167 // This also means that backup and restore will not be allowed. 168 if !config.DB.HasGlobalSettings() { 169 var err error 170 if mycnf, err = mysqlctl.NewMycnfFromFlags(tabletAlias.Uid); err != nil { 171 log.Exitf("mycnf read failed: %v", err) 172 } 173 socketFile = mycnf.SocketFile 174 } else { 175 log.Info("connection parameters were specified. Not loading my.cnf.") 176 } 177 178 // If connection parameters were specified, socketFile will be empty. 179 // Otherwise, the socketFile (read from mycnf) will be used to initialize 180 // dbconfigs. 181 config.DB.InitWithSocket(socketFile) 182 for _, cfg := range config.ExternalConnections { 183 cfg.InitWithSocket("") 184 } 185 return config, mycnf 186 } 187 188 // extractOnlineDDL extracts the gh-ost binary from this executable. gh-ost is appended 189 // to vttablet executable by `make build` with a go:embed 190 func extractOnlineDDL() error { 191 if binaryFileName, isOverride := onlineddl.GhostBinaryFileName(); !isOverride { 192 if err := os.WriteFile(binaryFileName, resources.GhostBinary, 0755); err != nil { 193 // One possibility of failure is that gh-ost is up and running. In that case, 194 // let's pause and check if the running gh-ost is exact same binary as the one we wish to extract. 195 foundBytes, _ := os.ReadFile(binaryFileName) 196 if bytes.Equal(resources.GhostBinary, foundBytes) { 197 // OK, it's the same binary, there is no need to extract the file anyway 198 return nil 199 } 200 return err 201 } 202 } 203 204 return nil 205 } 206 207 func createTabletServer(config *tabletenv.TabletConfig, ts *topo.Server, tabletAlias *topodatapb.TabletAlias) *tabletserver.TabletServer { 208 if tableACLConfig != "" { 209 // To override default simpleacl, other ACL plugins must set themselves to be default ACL factory 210 tableacl.Register("simpleacl", &simpleacl.Factory{}) 211 } else if enforceTableACLConfig { 212 log.Exit("table acl config has to be specified with table-acl-config flag because enforce-tableacl-config is set.") 213 } 214 // creates and registers the query service 215 qsc := tabletserver.NewTabletServer("", config, ts, tabletAlias) 216 servenv.OnRun(func() { 217 qsc.Register() 218 addStatusParts(qsc) 219 }) 220 servenv.OnClose(qsc.StopService) 221 qsc.InitACL(tableACLConfig, enforceTableACLConfig, tableACLConfigReloadInterval) 222 return qsc 223 }