command

package
v0.10.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 27, 2021 License: Apache-2.0 Imports: 18 Imported by: 0

Documentation

Overview

Package command contains the commands used by vtctldclient. It is intended only for use in vtctldclient's main package and entrypoint. The rest of this documentation is intended for maintainers.

Commands are grouped into files by the types of resources they interact with ( e.g. GetTablet, CreateTablet, DeleteTablet, GetTablets) or by what they do (e.g. PlannedReparentShard, EmergencyReparentShard, InitShardPrimary). Please add the command to the appropriate existing file, alphabetically, or create a new grouping if one does not exist.

The root command lives in root.go, and commands must attach themselves to this during an init function in order to be reachable from the CLI. root.go also contains the global variables available to any subcommand that are managed by the root command's pre- and post-run functions. Commands must not attempt to manage these, as that may conflict with Root's post-run cleanup actions. All commands should, at a minimum, use the commandCtx rather than creating their own context.Background to start, as it contains root tracing spans that would be lost.

Commands should not keep their logic in an anonymous function on the cobra.Command struct, but instead in a separate function that is assigned to RunE. Commands should strive to keep declaration, function definition, and flag initialization located as closely together as possible, to make the code easier to follow and understand (the global variables declared near Root are the exception here, not the rule). Commands should also prevent individual flag names from polluting the package namespace.

A good pattern we have found is to do the following:

package command

// (imports ...)

var (
	CreateTablet = &cobra.Command{
		Use: "CreateTablet [options] --keyspace=<keyspace> --shard=<shard-range> <tablet-alias> <tablet-type>",
		Args: cobra.ExactArgs(2),
		RunE: commandCreateTablet,
	}
	GetTablet = &cobra.Command{
		Use: "GetTablet <tablet-alias>",
		Args: cobra.ExactArgs(1),
		RunE: commandGetTablet,
	}
)

var createTabletOptions = struct {
	Opt1 string
	Opt2 bool
	Keyspace string
	Shard string
}{}

func commandCreateTablet(cmd *cobra.Command, args []string) error {
	aliasStr := cmd.Flags().Args(0)
	tabletTypeStr := cmd.Flags().Args(1)

	// do stuff with:
	// - client
	// - commandCtx
	// - createTabletOptions
	// - aliasStr
	// - tabletTypeStr

	return nil
}

// GetTablet takes no flags, so it needs no anonymous struct to store them
func commandGetTablet(cmd *cobra.Command, args []string) error {
	aliasStr := cmd.Flags().Arg(0)

	// do stuff with:
	// - client
	// - commandCtx
	// - aliasStr

	return nil
}

// finally, hook up all the commands in this file to Root, and add any flags
// to each of those commands

func init() {
	CreateTablet.Flags().StringVar(&createTabletOptions.Opt1, "opt1", "default", "help")
	CreateTablet.Flags().BoolVar(&createTabletOptions.Opt2, "opt2", false, "help")
	CreateTablet.Flags().StringVarP(&createTabletOptions.Keyspace, "keyspace", "k", "keyspace of tablet")
	CreateTablet.MarkFlagRequired("keyspace")
	CreateTablet.Flags().StringVarP(&createTabletOptions.Shard, "shard", "s", "shard range of tablet")
	CreateTablet.MarkFlagRequired("shard")
	Root.AddCommand(CreateTablet)

	Root.AddCommand(GetTablet)
}

A note on RunE and SilenceUsage:

We prefer using RunE over Run for the entrypoint to our subcommands, because it allows us return errors back up to the vtctldclient main function and do error handling, logging, and exit-code management once, in one place, rather than on a per-command basis. However, cobra treats errors returned from a command's RunE as usage errors, and therefore will print the command's full usage text to stderr when RunE returns non-nil, in addition to propagating that error back up to the result of the root command's Execute() method. This is decidedly not what we want. There is no plan to address this in cobra v1. 1

The suggested workaround for this issue is to set SilenceUsage: true, either on the root command or on every subcommand individually. This also does not work for vtctldclient, because not every flag can be parsed during pflag.Parse time, and for certain flags (mutually exclusive options, optional flags that require other flags to be set with them, etc) we do additional parsing and validation of flags in an individual subcommand. We want errors during this phase to be treated as usage errors, so setting SilenceUsage=true before this point would not cause usage text to be printed for us.

So, for us, we want to individually set cmd.SilenceUsage = true at *particular points* in each command, dependending on whether that command needs to do an additional parse & validation pass. In most cases, the command does not need to post-validate its options, and can set cmd.SilencUsage = true as their first line. We feel, though, that a line that reads "SilenceUsage = true" to be potentially confusing in how it reads. A maintainer without sufficient context may read this and say "Silence usage? We don't want that" and remove the lines, so we provide a wrapper function that communicates intent, cli.FinishedParsing, that each subcommand should call when they have transitioned from the parsing & validation phase of their entrypoint to the actual logic.

Index

Constants

This section is empty.

Variables

View Source
var (
	// GetCellInfoNames makes a GetCellInfoNames gRPC call to a vtctld.
	GetCellInfoNames = &cobra.Command{
		Use:  "GetCellInfoNames",
		Args: cobra.NoArgs,
		RunE: commandGetCellInfoNames,
	}
	// GetCellInfo makes a GetCellInfo gRPC call to a vtctld.
	GetCellInfo = &cobra.Command{
		Use:  "GetCellInfo cell",
		Args: cobra.ExactArgs(1),
		RunE: commandGetCellInfo,
	}
	// GetCellsAliases makes a GetCellsAliases gRPC call to a vtctld.
	GetCellsAliases = &cobra.Command{
		Use:  "GetCellsAliases",
		Args: cobra.NoArgs,
		RunE: commandGetCellsAliases,
	}
)
View Source
var (
	// CreateKeyspace makes a CreateKeyspace gRPC call to a vtctld.
	CreateKeyspace = &cobra.Command{
		Use:  "CreateKeyspace KEYSPACE_NAME [--force] [--sharding-column-name NAME --sharding-column-type TYPE] [--base-keyspace KEYSPACE --snapshot-timestamp TIME] [--served-from DB_TYPE:KEYSPACE ...]",
		Args: cobra.ExactArgs(1),
		RunE: commandCreateKeyspace,
	}
	// DeleteKeyspace makes a DeleteKeyspace gRPC call to a vtctld.
	DeleteKeyspace = &cobra.Command{
		Use:  "DeleteKeyspace KEYSPACE_NAME",
		Args: cobra.ExactArgs(1),
		RunE: commandDeleteKeyspace,
	}
	// FindAllShardsInKeyspace makes a FindAllShardsInKeyspace gRPC call to a vtctld.
	FindAllShardsInKeyspace = &cobra.Command{
		Use:     "FindAllShardsInKeyspace keyspace",
		Aliases: []string{"findallshardsinkeyspace"},
		Args:    cobra.ExactArgs(1),
		RunE:    commandFindAllShardsInKeyspace,
	}
	// GetKeyspace makes a GetKeyspace gRPC call to a vtctld.
	GetKeyspace = &cobra.Command{
		Use:     "GetKeyspace keyspace",
		Aliases: []string{"getkeyspace"},
		Args:    cobra.ExactArgs(1),
		RunE:    commandGetKeyspace,
	}
	// GetKeyspaces makes a GetKeyspaces gRPC call to a vtctld.
	GetKeyspaces = &cobra.Command{
		Use:     "GetKeyspaces",
		Aliases: []string{"getkeyspaces"},
		Args:    cobra.NoArgs,
		RunE:    commandGetKeyspaces,
	}
	// RemoveKeyspaceCell makes a RemoveKeyspaceCell gRPC call to a vtctld.
	RemoveKeyspaceCell = &cobra.Command{
		Use:  "RemoveKeyspaceCell <keyspace> <cell>",
		Args: cobra.ExactArgs(2),
		RunE: commandRemoveKeyspaceCell,
	}
)
View Source
var (
	// EmergencyReparentShard makes an EmergencyReparent gRPC call to a vtctld.
	EmergencyReparentShard = &cobra.Command{
		Use:  "EmergencyReparentShard <keyspace/shard>",
		Args: cobra.ExactArgs(1),
		Long: "Reparents the shard to the new primary. Assumes the old primary is dead and not responding",
		RunE: commandEmergencyReparentShard,
	}
	// InitShardPrimary makes an InitShardPrimary gRPC call to a vtctld.
	InitShardPrimary = &cobra.Command{
		Use:  "InitShardPrimary <keyspace/shard> <primary alias>",
		Args: cobra.ExactArgs(2),
		RunE: commandInitShardPrimary,
	}
	// PlannedReparentShard makes a PlannedReparentShard gRPC call to a vtctld.
	PlannedReparentShard = &cobra.Command{
		Use:  "PlannedReparentShard <keyspace/shard>",
		Args: cobra.ExactArgs(1),
		Long: "string",
		RunE: commandPlannedReparentShard,
	}
	// ReparentTablet makes a ReparentTablet gRPC call to a vtctld.
	ReparentTablet = &cobra.Command{
		Use: "ReparentTablet <alias>",
		Long: "Reparent a tablet to the current primary in the shard. This only works if the current replica position " +
			"matches the last known reparent action.",
		Args: cobra.ExactArgs(1),
		RunE: commandReparentTablet,
	}
	// TabletExternallyReparented makes a TabletExternallyReparented gRPC call
	// to a vtctld.
	TabletExternallyReparented = &cobra.Command{
		Use:  "TabletExternallyReparented <alias>",
		Args: cobra.ExactArgs(1),
		RunE: commandTabletExternallyReparented,
	}
)
View Source
var (
	// GetSrvKeyspaces makes a GetSrvKeyspaces gRPC call to a vtctld.
	GetSrvKeyspaces = &cobra.Command{
		Use:  "GetSrvKeyspaces <keyspace> [<cell> ...]",
		Args: cobra.MinimumNArgs(1),
		RunE: commandGetSrvKeyspaces,
	}
	// GetSrvVSchema makes a GetSrvVSchema gRPC call to a vtctld.
	GetSrvVSchema = &cobra.Command{
		Use:  "GetSrvVSchema cell",
		Args: cobra.ExactArgs(1),
		RunE: commandGetSrvVSchema,
	}
)
View Source
var (
	// CreateShard makes a CreateShard gRPC request to a vtctld.
	CreateShard = &cobra.Command{
		Use:  "CreateShard <keyspace/shard>",
		Args: cobra.ExactArgs(1),
		RunE: commandCreateShard,
	}
	// DeleteShards makes a DeleteShards gRPC request to a vtctld.
	DeleteShards = &cobra.Command{
		Use:  "DeleteShards <keyspace/shard> [<keyspace/shard> ...]",
		Args: cobra.MinimumNArgs(1),
		RunE: commandDeleteShards,
	}
	// GetShard makes a GetShard gRPC request to a vtctld.
	GetShard = &cobra.Command{
		Use:  "GetShard <keyspace/shard>",
		Args: cobra.ExactArgs(1),
		RunE: commandGetShard,
	}
	// RemoveShardCell makes a RemoveShardCell gRPC request to a vtctld.
	RemoveShardCell = &cobra.Command{
		Use:  "RemoveShardCell <keyspace/shard> <cell>",
		Args: cobra.ExactArgs(2),
		RunE: commandRemoveShardCell,
	}
	// ShardReplicationPositions makes a ShardReplicationPositions gRPC request
	// to a vtctld.
	ShardReplicationPositions = &cobra.Command{
		Use: "ShardReplicationPositions <keyspace/shard>",
		Long: `Shows the replication status of each tablet in the shard graph.
Output is sorted by tablet type, then replication position.
Use ctrl-C to interrupt the command and see partial results if needed.`,
		Args: cobra.ExactArgs(1),
		RunE: commandShardReplicationPositions,
	}
)
View Source
var (
	// ChangeTabletType makes a ChangeTabletType gRPC call to a vtctld.
	ChangeTabletType = &cobra.Command{
		Use:  "ChangeTabletType [--dry-run] TABLET_ALIAS TABLET_TYPE",
		Args: cobra.ExactArgs(2),
		RunE: commandChangeTabletType,
	}
	// DeleteTablets makes a DeleteTablets gRPC call to a vtctld.
	DeleteTablets = &cobra.Command{
		Use:  "DeleteTablets TABLET_ALIAS [ TABLET_ALIAS ... ]",
		Args: cobra.MinimumNArgs(1),
		RunE: commandDeleteTablets,
	}
	// GetTablet makes a GetTablet gRPC call to a vtctld.
	GetTablet = &cobra.Command{
		Use:  "GetTablet alias",
		Args: cobra.ExactArgs(1),
		RunE: commandGetTablet,
	}
	// GetTablets makes a GetTablets gRPC call to a vtctld.
	GetTablets = &cobra.Command{
		Use:  "GetTablets [--strict] [{--cell $c1 [--cell $c2 ...], --keyspace $ks [--shard $shard], --tablet-alias $alias}]",
		Args: cobra.NoArgs,
		RunE: commandGetTablets,
	}
)
View Source
var GetBackups = &cobra.Command{
	Use:  "GetBackups keyspace shard",
	Args: cobra.ExactArgs(2),
	RunE: commandGetBackups,
}

GetBackups makes a GetBackups gRPC call to a vtctld.

View Source
var GetSchema = &cobra.Command{
	Use:  "GetSchema [--tables TABLES ...] [--exclude-tables EXCLUDE_TABLES ...] [{--table-names-only | --table-sizes-only}] [--include-views] alias",
	Args: cobra.ExactArgs(1),
	RunE: commandGetSchema,
}

GetSchema makes a GetSchema gRPC call to a vtctld.

View Source
var (
	// GetVSchema makes a GetVSchema gRPC call to a vtctld.
	GetVSchema = &cobra.Command{
		Use:  "GetVSchema keyspace",
		Args: cobra.ExactArgs(1),
		RunE: commandGetVSchema,
	}
)
View Source
var (
	// GetWorkflows makes a GetWorkflows gRPC call to a vtctld.
	GetWorkflows = &cobra.Command{
		Use:  "GetWorkflows <keyspace>",
		Args: cobra.ExactArgs(1),
		RunE: commandGetWorkflows,
	}
)
View Source
var (

	// Root is the main entrypoint to the vtctldclient CLI.
	Root = &cobra.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)
				return err
			}

			client, err = vtctldclient.New("grpc", server)

			commandCtx, commandCancel = context.WithTimeout(context.Background(), actionTimeout)
			return err
		},

		PersistentPostRunE: func(cmd *cobra.Command, args []string) error {
			commandCancel()
			err := client.Close()
			trace.LogErrorsWhenClosing(traceCloser)
			return err
		},
		TraverseChildren: true,

		SilenceErrors: true,
	}
)

Functions

This section is empty.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL