Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions go/cmd/vtctlclient/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ func main() {
logutil.LogEvent(logger, e)
})
if err != nil {
if strings.Contains(err.Error(), "flag: help requested") {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This turns:

❯ vtctlclient -server "localhost:15999" ListAllTablets -h
Usage: ListAllTablets <cell name1>, <cell name2>, ...

Lists all tablets in an awk-friendly way.

ListAllTablets Error: rpc error: code = Unknown desc = flag: help requested
E0528 19:52:46.564223   77260 main.go:76] remote error: rpc error: code = Unknown desc = flag: help requested
❯ echo $?
1

Into

❯ vtctlclient -server "localhost:15999" ListAllTablets -h
Usage: ListAllTablets <cell name1>, <cell name2>, ...

Lists all tablets in an awk-friendly way.

❯ echo $?
0

return
}

errStr := strings.Replace(err.Error(), "remote error: ", "", -1)
fmt.Printf("%s Error: %s\n", flag.Arg(0), errStr)
log.Error(err)
Expand Down
104 changes: 104 additions & 0 deletions go/cmd/vtctldclient/internal/command/legacy_shim.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
Copyright 2021 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 command

import (
"context"
"flag"
"fmt"
"strings"

"github.com/spf13/cobra"

"vitess.io/vitess/go/cmd/vtctldclient/cli"
"vitess.io/vitess/go/vt/log"
"vitess.io/vitess/go/vt/logutil"
"vitess.io/vitess/go/vt/vtctl/vtctlclient"

logutilpb "vitess.io/vitess/go/vt/proto/logutil"
)

var (
// LegacyVtctlCommand provides a shim to make legacy ExecuteVtctlCommand
// RPCs. This allows users to use a single binary to make RPCs against both
// the new and old vtctld gRPC APIs.
LegacyVtctlCommand = &cobra.Command{
Use: "LegacyVtctlCommand -- <command> [flags ...] [args ...]",
Short: "Invoke a legacy vtctlclient command. Flag parsing is best effort.",
Args: cobra.ArbitraryArgs,
RunE: func(cmd *cobra.Command, args []string) error {
cli.FinishedParsing(cmd)
return runLegacyCommand(args)
},
Long: strings.TrimSpace(`
LegacyVtctlCommand uses the legacy vtctl grpc client to make an ExecuteVtctlCommand
rpc to a vtctld.

This command exists to support a smooth transition of any scripts that relied on
vtctlclient during the migration to the new vtctldclient, and will be removed,
following the Vitess project's standard deprecation cycle, once all commands
have been migrated to the new VtctldServer api.

To see the list of available legacy commands, run "LegacyVtctlCommand -- help".
Note that, as with the old client, this requires a running server, as the flag
parsing and help/usage text generation, is done server-side.

Also note that, in order to defer that flag parsing to the server side, you must
use the double-dash ("--") after the LegacyVtctlCommand subcommand string, or
the client-side flag parsing library we are using will attempt to parse those
flags (and fail).
`),
Example: strings.TrimSpace(`
LegacyVtctlCommand help # displays this help message
LegacyVtctlCommand -- help # displays help for supported legacy vtctl commands

# When using legacy command that take arguments, a double dash must be used
# before the first flag argument, like in the first example. The double dash may
# be used, however, at any point after the "LegacyVtctlCommand" string, as in
# the second example.
LegacyVtctlCommand AddCellInfo -- -server_address "localhost:1234" -root "/vitess/cell1"
LegacyVtctlCommand -- AddCellInfo -server_address "localhost:5678" -root "/vitess/cell1"`),
}
)

func runLegacyCommand(args []string) error {
// Duplicated (mostly) from go/cmd/vtctlclient/main.go.
logger := logutil.NewConsoleLogger()

ctx, cancel := context.WithTimeout(context.Background(), actionTimeout)
defer cancel()

err := vtctlclient.RunCommandAndWait(ctx, server, args, func(e *logutilpb.Event) {
logutil.LogEvent(logger, e)
})
if err != nil {
if strings.Contains(err.Error(), "flag: help requested") {
// Help is caught by SetHelpFunc, so we don't want to indicate this as an error.
return nil
}

errStr := strings.Replace(err.Error(), "remote error: ", "", -1)
fmt.Printf("%s Error: %s\n", flag.Arg(0), errStr)
log.Error(err)
}

return err
}

func init() {
Root.AddCommand(LegacyVtctlCommand)
}
16 changes: 12 additions & 4 deletions go/cmd/vtctldclient/internal/command/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import (
"github.com/spf13/cobra"

"vitess.io/vitess/go/trace"
"vitess.io/vitess/go/vt/log"
"vitess.io/vitess/go/vt/vtctl/vtctldclient"
)

Expand All @@ -44,9 +43,7 @@ var (
// command context for every command.
PersistentPreRunE: func(cmd *cobra.Command, args []string) (err error) {
traceCloser = trace.StartTracing("vtctldclient")
if server == "" {
err = errors.New("please specify -server <vtctld_host:vtctld_port> to specify the vtctld server to connect to")
log.Error(err)
if err := ensureServerArg(); err != nil {
return err
}

Expand Down Expand Up @@ -75,6 +72,17 @@ var (
}
)

var errNoServer = errors.New("please specify -server <vtctld_host:vtctld_port> to specify the vtctld server to connect to")

// ensureServerArg validates that --server was passed to the CLI.
func ensureServerArg() error {
if server == "" {
return errNoServer
}

return nil
}

func init() {
Root.PersistentFlags().StringVar(&server, "server", "", "server to use for connection")
Root.PersistentFlags().DurationVar(&actionTimeout, "action_timeout", time.Hour, "timeout for the total command")
Expand Down
23 changes: 23 additions & 0 deletions go/cmd/vtctldclient/plugin_grpcvtctlclient.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
Copyright 2021 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

// Imports and registers the gRPC vtctl client.

import (
_ "vitess.io/vitess/go/vt/vtctl/grpcvtctlclient"
)
41 changes: 41 additions & 0 deletions go/vt/vtctl/grpcclientcommon/dial_option.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
Copyright 2021 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 grpcclientcommon defines the flags shared by both grpcvtctlclient and
// grpcvtctldclient.
package grpcclientcommon

import (
"flag"

"google.golang.org/grpc"

"vitess.io/vitess/go/vt/grpcclient"
)

var (
cert = flag.String("vtctld_grpc_cert", "", "the cert to use to connect")
key = flag.String("vtctld_grpc_key", "", "the key to use to connect")
ca = flag.String("vtctld_grpc_ca", "", "the server ca to use to validate servers when connecting")
name = flag.String("vtctld_grpc_server_name", "", "the server name to use to validate server certificate")
)

// SecureDialOption returns a grpc.DialOption configured to use TLS (or
// insecure if no flags were set) based on the vtctld_grpc_* flags declared by
// this package.
func SecureDialOption() (grpc.DialOption, error) {
return grpcclient.SecureDialOption(*cert, *key, *ca, *name)
}
11 changes: 2 additions & 9 deletions go/vt/vtctl/grpcvtctlclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ limitations under the License.
package grpcvtctlclient

import (
"flag"
"time"

"context"
Expand All @@ -27,27 +26,21 @@ import (

"vitess.io/vitess/go/vt/grpcclient"
"vitess.io/vitess/go/vt/logutil"
"vitess.io/vitess/go/vt/vtctl/grpcclientcommon"
"vitess.io/vitess/go/vt/vtctl/vtctlclient"

logutilpb "vitess.io/vitess/go/vt/proto/logutil"
vtctldatapb "vitess.io/vitess/go/vt/proto/vtctldata"
vtctlservicepb "vitess.io/vitess/go/vt/proto/vtctlservice"
)

var (
cert = flag.String("vtctld_grpc_cert", "", "the cert to use to connect")
key = flag.String("vtctld_grpc_key", "", "the key to use to connect")
ca = flag.String("vtctld_grpc_ca", "", "the server ca to use to validate servers when connecting")
name = flag.String("vtctld_grpc_server_name", "", "the server name to use to validate server certificate")
)

type gRPCVtctlClient struct {
cc *grpc.ClientConn
c vtctlservicepb.VtctlClient
}

func gRPCVtctlClientFactory(addr string) (vtctlclient.VtctlClient, error) {
opt, err := grpcclient.SecureDialOption(*cert, *key, *ca, *name)
opt, err := grpcclientcommon.SecureDialOption()
if err != nil {
return nil, err
}
Expand Down
21 changes: 2 additions & 19 deletions go/vt/vtctl/grpcvtctldclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,34 +19,17 @@ limitations under the License.
package grpcvtctldclient

import (
"flag"

"google.golang.org/grpc"

"vitess.io/vitess/go/vt/grpcclient"
"vitess.io/vitess/go/vt/vtctl/grpcclientcommon"
"vitess.io/vitess/go/vt/vtctl/vtctldclient"

vtctlservicepb "vitess.io/vitess/go/vt/proto/vtctlservice"
)

const connClosedMsg = "grpc: the client connection is closed"

// (TODO:@amason) - These flags match exactly the flags used in grpcvtctlclient.
// If a program attempts to import both of these packages, it will panic during
// startup due to the duplicate flags.
//
// For everything else I've been doing a sed s/vtctl/vtctld, but I cannot do
// that here, since these flags are already "vtctld_*". My other options are to
// name them "vtctld2_*" or to omit them completely.
//
// Not to pitch project ideas in comments, but a nice project to solve
var (
cert = flag.String("vtctld_grpc_cert", "", "the cert to use to connect")
key = flag.String("vtctld_grpc_key", "", "the key to use to connect")
ca = flag.String("vtctld_grpc_ca", "", "the server ca to use to validate servers when connecting")
name = flag.String("vtctld_grpc_server_name", "", "the server name to use to validate server certificate")
)

type gRPCVtctldClient struct {
cc *grpc.ClientConn
c vtctlservicepb.VtctldClient
Expand All @@ -56,7 +39,7 @@ type gRPCVtctldClient struct {
//go:generate grpcvtctldclient -out client_gen.go

func gRPCVtctldClientFactory(addr string) (vtctldclient.VtctldClient, error) {
opt, err := grpcclient.SecureDialOption(*cert, *key, *ca, *name)
opt, err := grpcclientcommon.SecureDialOption()
if err != nil {
return nil, err
}
Expand Down