зеркало из https://github.com/github/vitess-gh.git
221 строка
8.1 KiB
Go
221 строка
8.1 KiB
Go
/*
|
|
Copyright 2020 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 (
|
|
"context"
|
|
"flag"
|
|
"io"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
"vitess.io/vitess/go/trace"
|
|
"vitess.io/vitess/go/vt/log"
|
|
"vitess.io/vitess/go/vt/servenv"
|
|
"vitess.io/vitess/go/vt/vtadmin"
|
|
"vitess.io/vitess/go/vt/vtadmin/cache"
|
|
"vitess.io/vitess/go/vt/vtadmin/cluster"
|
|
"vitess.io/vitess/go/vt/vtadmin/grpcserver"
|
|
vtadminhttp "vitess.io/vitess/go/vt/vtadmin/http"
|
|
"vitess.io/vitess/go/vt/vtadmin/http/debug"
|
|
"vitess.io/vitess/go/vt/vtadmin/rbac"
|
|
)
|
|
|
|
var (
|
|
opts grpcserver.Options
|
|
httpOpts vtadminhttp.Options
|
|
clusterConfigs cluster.ClustersFlag
|
|
clusterFileConfig cluster.FileConfig
|
|
defaultClusterConfig cluster.Config
|
|
enableDynamicClusters bool
|
|
|
|
rbacConfigPath string
|
|
enableRBAC bool
|
|
disableRBAC bool
|
|
|
|
cacheRefreshKey string
|
|
|
|
traceCloser io.Closer = &noopCloser{}
|
|
|
|
rootCmd = &cobra.Command{
|
|
Use: "vtadmin",
|
|
PreRun: func(cmd *cobra.Command, args []string) {
|
|
tmp := os.Args
|
|
os.Args = os.Args[0:1]
|
|
flag.Parse()
|
|
os.Args = tmp
|
|
|
|
if opts.EnableTracing || httpOpts.EnableTracing {
|
|
startTracing(cmd)
|
|
}
|
|
},
|
|
Run: run,
|
|
PostRun: func(cmd *cobra.Command, args []string) {
|
|
trace.LogErrorsWhenClosing(traceCloser)
|
|
},
|
|
Version: servenv.AppVersion.String(),
|
|
}
|
|
)
|
|
|
|
// fatal ensures the tracer is closed and final spans are sent before issuing
|
|
// a log.Fatal call with the given args.
|
|
func fatal(args ...any) {
|
|
trace.LogErrorsWhenClosing(traceCloser)
|
|
log.Fatal(args...)
|
|
}
|
|
|
|
// startTracing checks the value of --tracer and then starts tracing, populating
|
|
// the private global traceCloser
|
|
func startTracing(cmd *cobra.Command) {
|
|
tracer, err := cmd.Flags().GetString("tracer")
|
|
if err != nil {
|
|
log.Warningf("not starting tracer; err: %s", err)
|
|
return
|
|
}
|
|
|
|
if tracer == "" || tracer == "noop" {
|
|
log.Warningf("starting tracing with noop tracer")
|
|
}
|
|
|
|
traceCloser = trace.StartTracing("vtadmin")
|
|
}
|
|
|
|
func run(cmd *cobra.Command, args []string) {
|
|
bootSpan, ctx := trace.NewSpan(context.Background(), "vtadmin.boot")
|
|
defer bootSpan.Finish()
|
|
|
|
configs := clusterFileConfig.Combine(defaultClusterConfig, clusterConfigs)
|
|
clusters := make([]*cluster.Cluster, len(configs))
|
|
|
|
if len(configs) == 0 && !enableDynamicClusters {
|
|
bootSpan.Finish()
|
|
fatal("must specify at least one cluster")
|
|
}
|
|
|
|
var rbacConfig *rbac.Config
|
|
if disableRBAC {
|
|
rbacConfig = rbac.DefaultConfig()
|
|
} else if enableRBAC && rbacConfigPath != "" {
|
|
cfg, err := rbac.LoadConfig(rbacConfigPath)
|
|
if err != nil {
|
|
fatal(err)
|
|
}
|
|
|
|
rbacConfig = cfg
|
|
} else if enableRBAC && rbacConfigPath == "" {
|
|
fatal("must pass --rbac-config path when enabling rbac")
|
|
} else {
|
|
fatal("must explicitly enable or disable RBAC by passing --no-rbac or --rbac")
|
|
}
|
|
|
|
for i, cfg := range configs {
|
|
cluster, err := cfg.Cluster(ctx)
|
|
if err != nil {
|
|
bootSpan.Finish()
|
|
fatal(err)
|
|
}
|
|
|
|
clusters[i] = cluster
|
|
}
|
|
|
|
if cacheRefreshKey == "" {
|
|
log.Warningf("no cache-refresh-key set; forcing cache refreshes will not be possible")
|
|
}
|
|
cache.SetCacheRefreshKey(cacheRefreshKey)
|
|
|
|
s := vtadmin.NewAPI(clusters, vtadmin.Options{
|
|
GRPCOpts: opts,
|
|
HTTPOpts: httpOpts,
|
|
RBAC: rbacConfig,
|
|
EnableDynamicClusters: enableDynamicClusters,
|
|
})
|
|
bootSpan.Finish()
|
|
|
|
if err := s.ListenAndServe(); err != nil {
|
|
fatal(err)
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
// Common flags
|
|
rootCmd.Flags().StringVar(&opts.Addr, "addr", ":15000", "address to serve on")
|
|
rootCmd.Flags().DurationVar(&opts.CMuxReadTimeout, "lmux-read-timeout", time.Second, "how long to spend connection muxing")
|
|
rootCmd.Flags().DurationVar(&opts.LameDuckDuration, "lame-duck-duration", time.Second*5, "length of lame duck period at shutdown")
|
|
|
|
// Cluster config flags
|
|
rootCmd.Flags().Var(&clusterConfigs, "cluster", "per-cluster configuration. any values here take precedence over those in -cluster-defaults or -cluster-config")
|
|
rootCmd.Flags().Var(&clusterFileConfig, "cluster-config", "path to a yaml cluster configuration. see clusters.example.yaml") // (TODO:@amason) provide example config.
|
|
rootCmd.Flags().Var(&defaultClusterConfig, "cluster-defaults", "default options for all clusters")
|
|
rootCmd.Flags().BoolVar(&enableDynamicClusters, "enable-dynamic-clusters", false, "whether to enable dynamic clusters that are set by request header cookies or gRPC metadata")
|
|
|
|
// Tracing flags
|
|
trace.RegisterFlags(rootCmd.Flags()) // defined in go/vt/trace
|
|
rootCmd.Flags().BoolVar(&opts.EnableTracing, "grpc-tracing", false, "whether to enable tracing on the gRPC server")
|
|
rootCmd.Flags().BoolVar(&httpOpts.EnableTracing, "http-tracing", false, "whether to enable tracing on the HTTP server")
|
|
|
|
// gRPC server flags
|
|
rootCmd.Flags().BoolVar(&opts.AllowReflection, "grpc-allow-reflection", false, "whether to register the gRPC server for reflection; this is required to use tools like `grpc_cli`")
|
|
rootCmd.Flags().BoolVar(&opts.EnableChannelz, "grpc-enable-channelz", false, "whether to enable the channelz service on the gRPC server")
|
|
|
|
// HTTP server flags
|
|
rootCmd.Flags().BoolVar(&httpOpts.DisableCompression, "http-no-compress", false, "whether to disable compression of HTTP API responses")
|
|
rootCmd.Flags().BoolVar(&httpOpts.DisableDebug, "http-no-debug", false, "whether to disable /debug/pprof/* and /debug/env HTTP endpoints")
|
|
rootCmd.Flags().Var(&debug.OmitEnv, "http-debug-omit-env", "name of an environment variable to omit from /debug/env, if http debug endpoints are enabled. specify multiple times to omit multiple env vars")
|
|
rootCmd.Flags().Var(&debug.SanitizeEnv, "http-debug-sanitize-env", "name of an environment variable to sanitize in /debug/env, if http debug endpoints are enabled. specify multiple times to sanitize multiple env vars")
|
|
rootCmd.Flags().StringVar(&opts.MetricsEndpoint, "http-metrics-endpoint", "/metrics",
|
|
"HTTP endpoint to expose prometheus metrics on. Omit to disable scraping metrics. "+
|
|
"Using a path used by VTAdmin's http API is unsupported and causes undefined behavior.")
|
|
rootCmd.Flags().StringSliceVar(&httpOpts.CORSOrigins, "http-origin", []string{}, "repeated, comma-separated flag of allowed CORS origins. omit to disable CORS")
|
|
rootCmd.Flags().StringVar(&httpOpts.ExperimentalOptions.TabletURLTmpl,
|
|
"http-tablet-url-tmpl",
|
|
"https://{{ .Tablet.Hostname }}:80",
|
|
"[EXPERIMENTAL] Go template string to generate a reachable http(s) "+
|
|
"address for a tablet. Currently used to make passthrough "+
|
|
"requests to /debug/vars endpoints.",
|
|
)
|
|
|
|
// RBAC flags
|
|
rootCmd.Flags().StringVar(&rbacConfigPath, "rbac-config", "", "path to an RBAC config file. must be set if passing --rbac")
|
|
rootCmd.Flags().BoolVar(&enableRBAC, "rbac", false, "whether to enable RBAC. must be set if not passing --rbac")
|
|
rootCmd.Flags().BoolVar(&disableRBAC, "no-rbac", false, "whether to disable RBAC. must be set if not passing --no-rbac")
|
|
|
|
// Global cache flags (N.B. there are also cluster-specific cache flags)
|
|
cacheRefreshHelp := "instructs a request to ignore any cached data (if applicable) and refresh the cache;" +
|
|
"usable as an HTTP header named 'X-<key>' and as a gRPC metadata key '<key>'\n" +
|
|
"Note: any whitespace characters are replaced with hyphens."
|
|
rootCmd.Flags().StringVar(&cacheRefreshKey, "cache-refresh-key", "vt-cache-refresh", cacheRefreshHelp)
|
|
|
|
// glog flags, no better way to do this
|
|
rootCmd.Flags().AddGoFlag(flag.Lookup("v"))
|
|
rootCmd.Flags().AddGoFlag(flag.Lookup("logtostderr"))
|
|
rootCmd.Flags().AddGoFlag(flag.Lookup("alsologtostderr"))
|
|
rootCmd.Flags().AddGoFlag(flag.Lookup("stderrthreshold"))
|
|
rootCmd.Flags().AddGoFlag(flag.Lookup("log_dir"))
|
|
|
|
if err := rootCmd.Execute(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
log.Flush()
|
|
}
|
|
|
|
type noopCloser struct{}
|
|
|
|
func (nc *noopCloser) Close() error { return nil }
|