diff --git a/go/cmd/vtorc/cli/cli.go b/go/cmd/vtorc/cli/cli.go
new file mode 100644
index 00000000000..da9380eb625
--- /dev/null
+++ b/go/cmd/vtorc/cli/cli.go
@@ -0,0 +1,118 @@
+/*
+Copyright 2023 The Vitess Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package cli
+
+import (
+ "flag"
+ "fmt"
+
+ "github.com/spf13/cobra"
+
+ "vitess.io/vitess/go/acl"
+ _flag "vitess.io/vitess/go/internal/flag"
+ "vitess.io/vitess/go/viperutil"
+ viperdebug "vitess.io/vitess/go/viperutil/debug"
+ "vitess.io/vitess/go/vt/log"
+ "vitess.io/vitess/go/vt/servenv"
+ "vitess.io/vitess/go/vt/vtorc/config"
+ "vitess.io/vitess/go/vt/vtorc/inst"
+ "vitess.io/vitess/go/vt/vtorc/logic"
+ "vitess.io/vitess/go/vt/vtorc/server"
+)
+
+var (
+ configFile string
+ Main = &cobra.Command{
+ Use: "vtorc",
+ Short: "", // TODO
+ Args: cobra.NoArgs,
+ Version: servenv.AppVersion.String(),
+ PreRunE: func(cmd *cobra.Command, args []string) error {
+ _flag.TrickGlog()
+
+ watchCancel, err := viperutil.LoadConfig()
+ if err != nil {
+ return fmt.Errorf("%s: failed to read in config: %s", cmd.Name(), err)
+ }
+
+ servenv.OnTerm(watchCancel)
+ servenv.HTTPHandleFunc("/debug/config", viperdebug.HandlerFunc)
+ return nil
+ },
+ Run: run,
+ }
+)
+
+func run(cmd *cobra.Command, args []string) {
+ servenv.Init()
+ config.UpdateConfigValuesFromFlags()
+ inst.RegisterStats()
+
+ log.Info("starting vtorc")
+ if len(configFile) > 0 {
+ config.ForceRead(configFile)
+ } else {
+ config.Read("/etc/vtorc.conf.json", "conf/vtorc.conf.json", "vtorc.conf.json")
+ }
+ if config.Config.AuditToSyslog {
+ inst.EnableAuditSyslog()
+ }
+ config.MarkConfigurationLoaded()
+
+ // Log final config values to debug if something goes wrong.
+ config.LogConfigValues()
+ server.StartVTOrcDiscovery()
+
+ server.RegisterVTOrcAPIEndpoints()
+ servenv.OnRun(func() {
+ addStatusParts()
+ })
+
+ // For backward compatability, we require that VTOrc functions even when the --port flag is not provided.
+ // In this case, it should function like before but without the servenv pages.
+ // Therefore, currently we don't check for the --port flag to be necessary, but release 16+ that check
+ // can be added to always have the serenv page running in VTOrc.
+ servenv.RunDefault()
+}
+
+// addStatusParts adds UI parts to the /debug/status page of VTOrc
+func addStatusParts() {
+ servenv.AddStatusPart("Recent Recoveries", logic.TopologyRecoveriesTemplate, func() any {
+ recoveries, _ := logic.ReadRecentRecoveries(false, 0)
+ return recoveries
+ })
+}
+
+func init() {
+ servenv.RegisterDefaultFlags()
+ servenv.RegisterFlags()
+
+ Main.Flags().AddFlagSet(servenv.GetFlagSetFor("vtorc"))
+
+ // glog flags, no better way to do this
+ _flag.PreventGlogVFlagFromClobberingVersionFlagShorthand(Main.Flags())
+ Main.Flags().AddGoFlag(flag.Lookup("logtostderr"))
+ Main.Flags().AddGoFlag(flag.Lookup("alsologtostderr"))
+ Main.Flags().AddGoFlag(flag.Lookup("stderrthreshold"))
+ Main.Flags().AddGoFlag(flag.Lookup("log_dir"))
+
+ logic.RegisterFlags(Main.Flags())
+ server.RegisterFlags(Main.Flags())
+ config.RegisterFlags(Main.Flags())
+ acl.RegisterFlags(Main.Flags())
+ Main.Flags().StringVar(&configFile, "config", "", "config file name")
+}
diff --git a/go/cmd/vtorc/plugin_consultopo.go b/go/cmd/vtorc/cli/plugin_consultopo.go
similarity index 98%
rename from go/cmd/vtorc/plugin_consultopo.go
rename to go/cmd/vtorc/cli/plugin_consultopo.go
index 59d6774fdbc..a128f294a42 100644
--- a/go/cmd/vtorc/plugin_consultopo.go
+++ b/go/cmd/vtorc/cli/plugin_consultopo.go
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-package main
+package cli
// This plugin imports consultopo to register the consul implementation of TopoServer.
diff --git a/go/cmd/vtorc/plugin_etcd2topo.go b/go/cmd/vtorc/cli/plugin_etcd2topo.go
similarity index 98%
rename from go/cmd/vtorc/plugin_etcd2topo.go
rename to go/cmd/vtorc/cli/plugin_etcd2topo.go
index d99ef51d4af..5a51923cf00 100644
--- a/go/cmd/vtorc/plugin_etcd2topo.go
+++ b/go/cmd/vtorc/cli/plugin_etcd2topo.go
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-package main
+package cli
// This plugin imports etcd2topo to register the etcd2 implementation of TopoServer.
diff --git a/go/cmd/vtorc/plugin_grpctmclient.go b/go/cmd/vtorc/cli/plugin_grpctmclient.go
similarity index 98%
rename from go/cmd/vtorc/plugin_grpctmclient.go
rename to go/cmd/vtorc/cli/plugin_grpctmclient.go
index ce554da96df..8cd349c7f87 100644
--- a/go/cmd/vtorc/plugin_grpctmclient.go
+++ b/go/cmd/vtorc/cli/plugin_grpctmclient.go
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-package main
+package cli
// Imports and register the gRPC tabletmanager client
diff --git a/go/cmd/vtorc/plugin_prometheusbackend.go b/go/cmd/vtorc/cli/plugin_prometheusbackend.go
similarity index 98%
rename from go/cmd/vtorc/plugin_prometheusbackend.go
rename to go/cmd/vtorc/cli/plugin_prometheusbackend.go
index 868e097ade2..8cb6e034d8a 100644
--- a/go/cmd/vtorc/plugin_prometheusbackend.go
+++ b/go/cmd/vtorc/cli/plugin_prometheusbackend.go
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-package main
+package cli
// This plugin imports Prometheus to allow for instrumentation
// with the Prometheus client library
diff --git a/go/cmd/vtorc/plugin_zk2topo.go b/go/cmd/vtorc/cli/plugin_zk2topo.go
similarity index 98%
rename from go/cmd/vtorc/plugin_zk2topo.go
rename to go/cmd/vtorc/cli/plugin_zk2topo.go
index ebf385ec1af..d71a7e2e196 100644
--- a/go/cmd/vtorc/plugin_zk2topo.go
+++ b/go/cmd/vtorc/cli/plugin_zk2topo.go
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-package main
+package cli
// Imports and register the zk2 TopologyServer
diff --git a/go/cmd/vtorc/docgen/main.go b/go/cmd/vtorc/docgen/main.go
new file mode 100644
index 00000000000..22daccab302
--- /dev/null
+++ b/go/cmd/vtorc/docgen/main.go
@@ -0,0 +1,37 @@
+/*
+Copyright 2023 The Vitess Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package main
+
+import (
+ "github.com/spf13/cobra"
+
+ "vitess.io/vitess/go/cmd/internal/docgen"
+ "vitess.io/vitess/go/cmd/vtorc/cli"
+)
+
+func main() {
+ var dir string
+ cmd := cobra.Command{
+ Use: "docgen [-d
]",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return docgen.GenerateMarkdownTree(cli.Main, dir)
+ },
+ }
+
+ cmd.Flags().StringVarP(&dir, "dir", "d", "doc", "output directory to write documentation")
+ _ = cmd.Execute()
+}
diff --git a/go/cmd/vtorc/main.go b/go/cmd/vtorc/main.go
index 6c27c17a29d..101265b16c5 100644
--- a/go/cmd/vtorc/main.go
+++ b/go/cmd/vtorc/main.go
@@ -17,120 +17,18 @@
package main
import (
- "strings"
-
_ "github.com/go-sql-driver/mysql"
- "github.com/spf13/pflag"
_ "modernc.org/sqlite"
- "vitess.io/vitess/go/acl"
+ "vitess.io/vitess/go/cmd/vtorc/cli"
"vitess.io/vitess/go/vt/log"
- "vitess.io/vitess/go/vt/servenv"
- "vitess.io/vitess/go/vt/vtorc/config"
- "vitess.io/vitess/go/vt/vtorc/inst"
- "vitess.io/vitess/go/vt/vtorc/logic"
- "vitess.io/vitess/go/vt/vtorc/server"
)
-// transformArgsForPflag turns a slice of raw args passed on the command line,
-// possibly incompatible with pflag (because the user is expecting stdlib flag
-// parsing behavior) and transforms them into the arguments that should have
-// been passed to conform to pflag parsing behavior.
-//
-// the primary function is to catch any cases where the user specified a longopt
-// with only a single hyphen (e.g. `-myflag`) and correct it to be
-// double-hyphenated.
-//
-// note that this transformation does _not_ actually validate the arguments; for
-// example if the user specifies `--myflag`, but the FlagSet has no such flag
-// defined, that will still appear in the returned result and will (correctly)
-// cause a parse error later on in `main`, at which point the CLI usage will
-// be printed.
-//
-// note also that this transformation is incomplete. pflag allows interspersing
-// of flag and positional arguments, whereas stdlib flag does not. however, for
-// vtorc specifically, with the exception of `vtorc help `, the CLI only
-// consumes flag arguments (in other words, there are no supported subcommands),
-// so this is a non-issue, and is not implemented here in order to make this
-// function a bit simpler.
-func transformArgsForPflag(fs *pflag.FlagSet, args []string) (result []string) {
- for i, arg := range args {
- switch {
- case arg == "--":
- // pflag stops parsing at `--`, so we're done transforming the CLI
- // arguments. Just append everything remaining and be done.
- result = append(result, args[i:]...)
- return result
- case strings.HasPrefix(arg, "--"):
- // Long-hand flag. Append it and continue.
- result = append(result, arg)
- case strings.HasPrefix(arg, "-"):
- // Most complex case. This is either:
- // 1. A legacy long-hand flag that needs a double-dash (e.g. `-myflag` => `--myflag`).
- // 2. One _or more_ pflag shortopts all shoved together (think `rm -rf` as `rm -r -f`).
- //
- // In the latter case, we don't need to do any transformations, but
- // in the former, we do.
- name := strings.SplitN(arg[1:], "=", 2)[0] // discard any potential value (`-myflag` and `-myflag=10` both have the name of `myflag`)
- if fs.Lookup(name) != nil || name == "help" {
- // Case 1: We have a long opt with this name, so we need to
- // prepend an additional hyphen.
- result = append(result, "-"+arg)
- } else {
- // Case 2: No transformation needed.
- result = append(result, arg)
- }
- default:
- // Just a flag argument. Nothing to transform.
- result = append(result, arg)
- }
- }
-
- return result
-}
-
// main is the application's entry point. It will spawn an HTTP interface.
func main() {
- servenv.RegisterDefaultFlags()
- servenv.RegisterFlags()
-
- var configFile string
- servenv.OnParseFor("vtorc", func(fs *pflag.FlagSet) {
- logic.RegisterFlags(fs)
- server.RegisterFlags(fs)
- config.RegisterFlags(fs)
- acl.RegisterFlags(fs)
+ // TODO: viperutil.BindFlags()
- fs.StringVar(&configFile, "config", "", "config file name")
- })
- servenv.ParseFlags("vtorc")
- servenv.Init()
- config.UpdateConfigValuesFromFlags()
- inst.RegisterStats()
-
- log.Info("starting vtorc")
- if len(configFile) > 0 {
- config.ForceRead(configFile)
- } else {
- config.Read("/etc/vtorc.conf.json", "conf/vtorc.conf.json", "vtorc.conf.json")
- }
- if config.Config.AuditToSyslog {
- inst.EnableAuditSyslog()
+ if err := cli.Main.Execute(); err != nil {
+ log.Exit(err)
}
- config.MarkConfigurationLoaded()
-
- // Log final config values to debug if something goes wrong.
- config.LogConfigValues()
- server.StartVTOrcDiscovery()
-
- server.RegisterVTOrcAPIEndpoints()
- servenv.OnRun(func() {
- addStatusParts()
- })
-
- // For backward compatability, we require that VTOrc functions even when the --port flag is not provided.
- // In this case, it should function like before but without the servenv pages.
- // Therefore, currently we don't check for the --port flag to be necessary, but release 16+ that check
- // can be added to always have the serenv page running in VTOrc.
- servenv.RunDefault()
}
diff --git a/go/cmd/vtorc/main_test.go b/go/cmd/vtorc/main_test.go
deleted file mode 100644
index 5bbdcdaf981..00000000000
--- a/go/cmd/vtorc/main_test.go
+++ /dev/null
@@ -1,48 +0,0 @@
-package main
-
-import (
- "strings"
- "testing"
-
- "github.com/spf13/pflag"
- "github.com/stretchr/testify/assert"
-)
-
-func Test_transformArgsForPflag(t *testing.T) {
- fs := pflag.NewFlagSet("test", pflag.ContinueOnError)
- fs.String("foobar", "baz", "")
- fs.StringP("name", "n", "", "")
- fs.BoolP("debug", "d", true, "")
-
- tests := []struct {
- args []string
- transformed []string
- }{
- {
- args: []string{"--foobar=hello", "--name", "myname", "-d"},
- transformed: []string{"--foobar=hello", "--name", "myname", "-d"},
- },
- {
- args: []string{"-foobar=hello", "-name", "myname", "-d"},
- transformed: []string{"--foobar=hello", "--name", "myname", "-d"},
- },
- {
- args: []string{"--", "-foobar=hello"},
- transformed: []string{"--", "-foobar=hello"},
- },
- {
- args: []string{"-dn"}, // combined shortopts
- transformed: []string{"-dn"},
- },
- }
-
- for _, tt := range tests {
- tt := tt
- name := strings.Join(tt.args, " ")
-
- t.Run(name, func(t *testing.T) {
- got := transformArgsForPflag(fs, tt.args)
- assert.Equal(t, tt.transformed, got)
- })
- }
-}
diff --git a/go/cmd/vtorc/status.go b/go/cmd/vtorc/status.go
deleted file mode 100644
index a4d8a59d3fc..00000000000
--- a/go/cmd/vtorc/status.go
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
-Copyright 2022 The Vitess Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreedto in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package main
-
-import (
- "vitess.io/vitess/go/vt/servenv"
- "vitess.io/vitess/go/vt/vtorc/logic"
-)
-
-// addStatusParts adds UI parts to the /debug/status page of VTOrc
-func addStatusParts() {
- servenv.AddStatusPart("Recent Recoveries", logic.TopologyRecoveriesTemplate, func() any {
- recoveries, _ := logic.ReadRecentRecoveries(false, 0)
- return recoveries
- })
-}
diff --git a/go/flags/endtoend/vtorc.txt b/go/flags/endtoend/vtorc.txt
index 5a49255fd95..74f4f37956c 100644
--- a/go/flags/endtoend/vtorc.txt
+++ b/go/flags/endtoend/vtorc.txt
@@ -1,4 +1,7 @@
-Usage of vtorc:
+Usage:
+ vtorc [flags]
+
+Flags:
--allow-emergency-reparent Whether VTOrc should be allowed to run emergency reparent operation when it detects a dead primary (default true)
--alsologtostderr log to standard error as well as files
--audit-file-location string File location where the audit logs are to be stored
@@ -25,13 +28,12 @@ Usage of vtorc:
--grpc_keepalive_timeout duration After having pinged for keepalive check, the client waits for a duration of Timeout and if no activity is seen even after that the connection is closed. (default 10s)
--grpc_max_message_size int Maximum allowed RPC message size. Larger messages will be rejected by gRPC with the error 'exceeding the max size'. (default 16777216)
--grpc_prometheus Enable gRPC monitoring with Prometheus.
- -h, --help display usage and exit
+ -h, --help help for vtorc
--instance-poll-time duration Timer duration on which VTOrc refreshes MySQL information (default 5s)
--keep_logs duration keep logs for this long (using ctime) (zero to keep forever)
--keep_logs_by_mtime duration keep logs for this long (using mtime) (zero to keep forever)
--lameduck-period duration keep running at least this long after SIGTERM before stopping (default 50ms)
--lock-timeout duration Maximum time for which a shard/keyspace lock can be acquired for (default 45s)
- --log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0)
--log_dir string If non-empty, write log files in this directory
--log_err_stacks log stack traces for errors
--log_rotate_max_size uint size in bytes at which logs are rotated (glog.MaxSize) (default 1887436800)
@@ -87,5 +89,4 @@ Usage of vtorc:
--topo_zk_tls_key string the key to use to connect to the zk topo server, enables TLS
--v Level log level for V logs
-v, --version print binary version
- --vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging
--wait-replicas-timeout duration Duration for which to wait for replica's to respond when issuing RPCs (default 30s)
diff --git a/go/internal/flag/flag.go b/go/internal/flag/flag.go
index 6f087143610..ade4907e573 100644
--- a/go/internal/flag/flag.go
+++ b/go/internal/flag/flag.go
@@ -42,7 +42,7 @@ import (
//
// See VEP-4, phase 1 for details: https://github.com/vitessio/enhancements/blob/c766ea905e55409cddeb666d6073cd2ac4c9783e/veps/vep-4.md#phase-1-preparation
func Parse(fs *flag.FlagSet) {
- preventGlogVFlagFromClobberingVersionFlagShorthand(fs)
+ PreventGlogVFlagFromClobberingVersionFlagShorthand(fs)
fs.AddGoFlagSet(goflag.CommandLine)
if fs.Lookup("help") == nil {
@@ -115,7 +115,7 @@ func TrickGlog() {
//
// IMPORTANT: This must be called prior to AddGoFlagSet in both Parse and
// ParseFlagsForTest.
-func preventGlogVFlagFromClobberingVersionFlagShorthand(fs *flag.FlagSet) {
+func PreventGlogVFlagFromClobberingVersionFlagShorthand(fs *flag.FlagSet) {
// N.B. we use goflag.Lookup instead of this package's Lookup, because we
// explicitly want to check only the goflags.
if f := goflag.Lookup("v"); f != nil {
@@ -178,7 +178,7 @@ func ParseFlagsForTest() {
}
// parse remaining flags including the log-related ones like --alsologtostderr
- preventGlogVFlagFromClobberingVersionFlagShorthand(flag.CommandLine)
+ PreventGlogVFlagFromClobberingVersionFlagShorthand(flag.CommandLine)
flag.CommandLine.AddGoFlagSet(goflag.CommandLine)
flag.Parse()
}