vitess.io/vitess@v0.16.2/go/cmd/vtctldclient/command/keyspaces.go (about)

     1  /*
     2  Copyright 2021 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  package command
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"time"
    23  
    24  	"github.com/spf13/cobra"
    25  
    26  	"vitess.io/vitess/go/cmd/vtctldclient/cli"
    27  	"vitess.io/vitess/go/vt/logutil"
    28  	"vitess.io/vitess/go/vt/topo"
    29  
    30  	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
    31  	vtctldatapb "vitess.io/vitess/go/vt/proto/vtctldata"
    32  	"vitess.io/vitess/go/vt/proto/vttime"
    33  )
    34  
    35  var (
    36  	// CreateKeyspace makes a CreateKeyspace gRPC call to a vtctld.
    37  	CreateKeyspace = &cobra.Command{
    38  		Use:   "CreateKeyspace <keyspace> [--force|-f] [--type KEYSPACE_TYPE] [--base-keyspace KEYSPACE --snapshot-timestamp TIME] [--served-from DB_TYPE:KEYSPACE ...]  [--durability-policy <policy_name>]",
    39  		Short: "Creates the specified keyspace in the topology.",
    40  		Long: `Creates the specified keyspace in the topology.
    41  	
    42  For a SNAPSHOT keyspace, the request must specify the name of a base keyspace,
    43  as well as a snapshot time.`,
    44  		DisableFlagsInUseLine: true,
    45  		Args:                  cobra.ExactArgs(1),
    46  		RunE:                  commandCreateKeyspace,
    47  	}
    48  	// DeleteKeyspace makes a DeleteKeyspace gRPC call to a vtctld.
    49  	DeleteKeyspace = &cobra.Command{
    50  		Use:   "DeleteKeyspace [--recursive|-r] [--force|-f] <keyspace>",
    51  		Short: "Deletes the specified keyspace from the topology.",
    52  		Long: `Deletes the specified keyspace from the topology.
    53  
    54  In recursive mode, it also recursively deletes all shards in the keyspace.
    55  Otherwise, the keyspace must be empty (have no shards), or returns an error.`,
    56  		DisableFlagsInUseLine: true,
    57  		Args:                  cobra.ExactArgs(1),
    58  		RunE:                  commandDeleteKeyspace,
    59  	}
    60  	// FindAllShardsInKeyspace makes a FindAllShardsInKeyspace gRPC call to a vtctld.
    61  	FindAllShardsInKeyspace = &cobra.Command{
    62  		Use:                   "FindAllShardsInKeyspace <keyspace>",
    63  		Short:                 "Returns a map of shard names to shard references for a given keyspace.",
    64  		DisableFlagsInUseLine: true,
    65  		Aliases:               []string{"findallshardsinkeyspace"},
    66  		Args:                  cobra.ExactArgs(1),
    67  		RunE:                  commandFindAllShardsInKeyspace,
    68  	}
    69  	// GetKeyspace makes a GetKeyspace gRPC call to a vtctld.
    70  	GetKeyspace = &cobra.Command{
    71  		Use:                   "GetKeyspace <keyspace>",
    72  		Short:                 "Returns information about the given keyspace from the topology.",
    73  		DisableFlagsInUseLine: true,
    74  		Aliases:               []string{"getkeyspace"},
    75  		Args:                  cobra.ExactArgs(1),
    76  		RunE:                  commandGetKeyspace,
    77  	}
    78  	// GetKeyspaces makes a GetKeyspaces gRPC call to a vtctld.
    79  	GetKeyspaces = &cobra.Command{
    80  		Use:                   "GetKeyspaces",
    81  		Short:                 "Returns information about every keyspace in the topology.",
    82  		DisableFlagsInUseLine: true,
    83  		Aliases:               []string{"getkeyspaces"},
    84  		Args:                  cobra.NoArgs,
    85  		RunE:                  commandGetKeyspaces,
    86  	}
    87  	// RemoveKeyspaceCell makes a RemoveKeyspaceCell gRPC call to a vtctld.
    88  	RemoveKeyspaceCell = &cobra.Command{
    89  		Use:                   "RemoveKeyspaceCell [--force|-f] [--recursive|-r] <keyspace> <cell>",
    90  		Short:                 "Removes the specified cell from the Cells list for all shards in the specified keyspace (by calling RemoveShardCell on every shard). It also removes the SrvKeyspace for that keyspace in that cell.",
    91  		DisableFlagsInUseLine: true,
    92  		Args:                  cobra.ExactArgs(2),
    93  		RunE:                  commandRemoveKeyspaceCell,
    94  	}
    95  	// SetKeyspaceDurabilityPolicy makes a SetKeyspaceDurabilityPolicy gRPC call to a vtcltd.
    96  	SetKeyspaceDurabilityPolicy = &cobra.Command{
    97  		Use:   "SetKeyspaceDurabilityPolicy [--durability-policy=policy_name] <keyspace name>",
    98  		Short: "Sets the durability-policy used by the specified keyspace.",
    99  		Long: `Sets the durability-policy used by the specified keyspace. 
   100  Durability policy governs the durability of the keyspace by describing which tablets should be sending semi-sync acknowledgements to the primary.
   101  Possible values include 'semi_sync', 'none' and others as dictated by registered plugins.
   102  
   103  To set the durability policy of customer keyspace to semi_sync, you would use the following command:
   104  SetKeyspaceDurabilityPolicy --durability-policy='semi_sync' customer`,
   105  		DisableFlagsInUseLine: true,
   106  		Args:                  cobra.ExactArgs(1),
   107  		RunE:                  commandSetKeyspaceDurabilityPolicy,
   108  	}
   109  	// ValidateSchemaKeyspace makes a ValidateSchemaKeyspace gRPC call to a vtctld.
   110  	ValidateSchemaKeyspace = &cobra.Command{
   111  		Use:                   "ValidateSchemaKeyspace [--exclude-tables=<exclude_tables>] [--include-views] [--skip-no-primary] [--include-vschema] <keyspace>",
   112  		Short:                 "Validates that the schema on the primary tablet for shard 0 matches the schema on all other tablets in the keyspace.",
   113  		DisableFlagsInUseLine: true,
   114  		Aliases:               []string{"validateschemakeyspace"},
   115  		Args:                  cobra.ExactArgs(1),
   116  		RunE:                  commandValidateSchemaKeyspace,
   117  	}
   118  	// ValidateVersionKeyspace makes a ValidateVersionKeyspace gRPC call to a vtctld.
   119  	ValidateVersionKeyspace = &cobra.Command{
   120  		Use:                   "ValidateVersionKeyspace <keyspace>",
   121  		Short:                 "Validates that the version on the primary tablet of shard 0 matches all of the other tablets in the keyspace.",
   122  		DisableFlagsInUseLine: true,
   123  		Aliases:               []string{"validateversionkeyspace"},
   124  		Args:                  cobra.ExactArgs(1),
   125  		RunE:                  commandValidateVersionKeyspace,
   126  	}
   127  )
   128  
   129  var createKeyspaceOptions = struct {
   130  	Force             bool
   131  	AllowEmptyVSchema bool
   132  
   133  	ServedFromsMap cli.StringMapValue
   134  
   135  	KeyspaceType      cli.KeyspaceTypeFlag
   136  	BaseKeyspace      string
   137  	SnapshotTimestamp string
   138  	DurabilityPolicy  string
   139  }{
   140  	KeyspaceType: cli.KeyspaceTypeFlag(topodatapb.KeyspaceType_NORMAL),
   141  }
   142  
   143  func commandCreateKeyspace(cmd *cobra.Command, args []string) error {
   144  	name := cmd.Flags().Arg(0)
   145  
   146  	switch topodatapb.KeyspaceType(createKeyspaceOptions.KeyspaceType) {
   147  	case topodatapb.KeyspaceType_NORMAL, topodatapb.KeyspaceType_SNAPSHOT:
   148  	default:
   149  		return fmt.Errorf("invalid keyspace type passed to --type: %v", createKeyspaceOptions.KeyspaceType)
   150  	}
   151  
   152  	var snapshotTime *vttime.Time
   153  	if topodatapb.KeyspaceType(createKeyspaceOptions.KeyspaceType) == topodatapb.KeyspaceType_SNAPSHOT {
   154  		if createKeyspaceOptions.DurabilityPolicy != "none" {
   155  			return errors.New("--durability-policy cannot be specified while creating a snapshot keyspace")
   156  		}
   157  
   158  		if createKeyspaceOptions.BaseKeyspace == "" {
   159  			return errors.New("--base-keyspace is required for a snapshot keyspace")
   160  		}
   161  
   162  		if createKeyspaceOptions.SnapshotTimestamp == "" {
   163  			return errors.New("--snapshot-timestamp is required for a snapshot keyspace")
   164  		}
   165  
   166  		t, err := time.Parse(time.RFC3339, createKeyspaceOptions.SnapshotTimestamp)
   167  		if err != nil {
   168  			return fmt.Errorf("cannot parse --snapshot-timestamp as RFC3339: %w", err)
   169  		}
   170  
   171  		if now := time.Now(); t.After(now) {
   172  			return fmt.Errorf("--snapshot-time cannot be in the future; snapshot = %v, now = %v", t, now)
   173  		}
   174  
   175  		snapshotTime = logutil.TimeToProto(t)
   176  	}
   177  
   178  	cli.FinishedParsing(cmd)
   179  
   180  	req := &vtctldatapb.CreateKeyspaceRequest{
   181  		Name:              name,
   182  		Force:             createKeyspaceOptions.Force,
   183  		AllowEmptyVSchema: createKeyspaceOptions.AllowEmptyVSchema,
   184  		Type:              topodatapb.KeyspaceType(createKeyspaceOptions.KeyspaceType),
   185  		BaseKeyspace:      createKeyspaceOptions.BaseKeyspace,
   186  		SnapshotTime:      snapshotTime,
   187  		DurabilityPolicy:  createKeyspaceOptions.DurabilityPolicy,
   188  	}
   189  
   190  	for n, v := range createKeyspaceOptions.ServedFromsMap.StringMapValue {
   191  		tt, err := topo.ParseServingTabletType(n)
   192  		if err != nil {
   193  			return err
   194  		}
   195  
   196  		req.ServedFroms = append(req.ServedFroms, &topodatapb.Keyspace_ServedFrom{
   197  			TabletType: tt,
   198  			Keyspace:   v,
   199  		})
   200  	}
   201  
   202  	resp, err := client.CreateKeyspace(commandCtx, req)
   203  	if err != nil {
   204  		return err
   205  	}
   206  
   207  	data, err := cli.MarshalJSON(resp.Keyspace)
   208  	if err != nil {
   209  		return err
   210  	}
   211  
   212  	fmt.Printf("Successfully created keyspace %s. Result:\n%s\n", name, data)
   213  
   214  	return nil
   215  }
   216  
   217  var deleteKeyspaceOptions = struct {
   218  	Recursive bool
   219  	Force     bool
   220  }{}
   221  
   222  func commandDeleteKeyspace(cmd *cobra.Command, args []string) error {
   223  	cli.FinishedParsing(cmd)
   224  
   225  	ks := cmd.Flags().Arg(0)
   226  	_, err := client.DeleteKeyspace(commandCtx, &vtctldatapb.DeleteKeyspaceRequest{
   227  		Keyspace:  ks,
   228  		Recursive: deleteKeyspaceOptions.Recursive,
   229  		Force:     deleteKeyspaceOptions.Force,
   230  	})
   231  
   232  	if err != nil {
   233  		return fmt.Errorf("DeleteKeyspace(%v) error: %w; please check the topo", ks, err)
   234  	}
   235  
   236  	fmt.Printf("Successfully deleted keyspace %v.\n", ks)
   237  
   238  	return nil
   239  }
   240  
   241  func commandFindAllShardsInKeyspace(cmd *cobra.Command, args []string) error {
   242  	cli.FinishedParsing(cmd)
   243  
   244  	ks := cmd.Flags().Arg(0)
   245  	resp, err := client.FindAllShardsInKeyspace(commandCtx, &vtctldatapb.FindAllShardsInKeyspaceRequest{
   246  		Keyspace: ks,
   247  	})
   248  
   249  	if err != nil {
   250  		return err
   251  	}
   252  
   253  	data, err := cli.MarshalJSON(resp)
   254  	if err != nil {
   255  		return err
   256  	}
   257  
   258  	fmt.Printf("%s\n", data)
   259  	return nil
   260  }
   261  
   262  func commandGetKeyspace(cmd *cobra.Command, args []string) error {
   263  	cli.FinishedParsing(cmd)
   264  
   265  	ks := cmd.Flags().Arg(0)
   266  	resp, err := client.GetKeyspace(commandCtx, &vtctldatapb.GetKeyspaceRequest{
   267  		Keyspace: ks,
   268  	})
   269  	if err != nil {
   270  		return err
   271  	}
   272  
   273  	data, err := cli.MarshalJSON(resp.Keyspace)
   274  	if err != nil {
   275  		return err
   276  	}
   277  
   278  	fmt.Printf("%s\n", data)
   279  
   280  	return nil
   281  }
   282  
   283  func commandGetKeyspaces(cmd *cobra.Command, args []string) error {
   284  	cli.FinishedParsing(cmd)
   285  
   286  	resp, err := client.GetKeyspaces(commandCtx, &vtctldatapb.GetKeyspacesRequest{})
   287  	if err != nil {
   288  		return err
   289  	}
   290  
   291  	data, err := cli.MarshalJSON(resp.Keyspaces)
   292  	if err != nil {
   293  		return err
   294  	}
   295  
   296  	fmt.Printf("%s\n", data)
   297  
   298  	return nil
   299  }
   300  
   301  var removeKeyspaceCellOptions = struct {
   302  	Force     bool
   303  	Recursive bool
   304  }{}
   305  
   306  func commandRemoveKeyspaceCell(cmd *cobra.Command, args []string) error {
   307  	cli.FinishedParsing(cmd)
   308  
   309  	keyspace := cmd.Flags().Arg(0)
   310  	cell := cmd.Flags().Arg(1)
   311  
   312  	_, err := client.RemoveKeyspaceCell(commandCtx, &vtctldatapb.RemoveKeyspaceCellRequest{
   313  		Keyspace:  keyspace,
   314  		Cell:      cell,
   315  		Force:     removeKeyspaceCellOptions.Force,
   316  		Recursive: removeKeyspaceCellOptions.Recursive,
   317  	})
   318  
   319  	if err != nil {
   320  		return err
   321  	}
   322  
   323  	fmt.Printf("Successfully removed keyspace %s from cell %s\n", keyspace, cell)
   324  
   325  	return nil
   326  }
   327  
   328  var setKeyspaceDurabilityPolicyOptions = struct {
   329  	DurabilityPolicy string
   330  }{}
   331  
   332  func commandSetKeyspaceDurabilityPolicy(cmd *cobra.Command, args []string) error {
   333  	keyspace := cmd.Flags().Arg(0)
   334  	cli.FinishedParsing(cmd)
   335  
   336  	resp, err := client.SetKeyspaceDurabilityPolicy(commandCtx, &vtctldatapb.SetKeyspaceDurabilityPolicyRequest{
   337  		Keyspace:         keyspace,
   338  		DurabilityPolicy: setKeyspaceDurabilityPolicyOptions.DurabilityPolicy,
   339  	})
   340  	if err != nil {
   341  		return err
   342  	}
   343  
   344  	data, err := cli.MarshalJSON(resp)
   345  	if err != nil {
   346  		return err
   347  	}
   348  
   349  	fmt.Printf("%s\n", data)
   350  	return nil
   351  }
   352  
   353  var validateSchemaKeyspaceOptions = struct {
   354  	ExcludeTables  []string
   355  	IncludeViews   bool
   356  	SkipNoPrimary  bool
   357  	IncludeVSchema bool
   358  }{}
   359  
   360  func commandValidateSchemaKeyspace(cmd *cobra.Command, args []string) error {
   361  	cli.FinishedParsing(cmd)
   362  
   363  	ks := cmd.Flags().Arg(0)
   364  	resp, err := client.ValidateSchemaKeyspace(commandCtx, &vtctldatapb.ValidateSchemaKeyspaceRequest{
   365  		Keyspace:       ks,
   366  		ExcludeTables:  validateSchemaKeyspaceOptions.ExcludeTables,
   367  		IncludeVschema: validateSchemaKeyspaceOptions.IncludeVSchema,
   368  		SkipNoPrimary:  validateSchemaKeyspaceOptions.SkipNoPrimary,
   369  		IncludeViews:   validateSchemaKeyspaceOptions.IncludeViews,
   370  	})
   371  
   372  	if err != nil {
   373  		return err
   374  	}
   375  
   376  	data, err := cli.MarshalJSON(resp)
   377  	if err != nil {
   378  		return err
   379  	}
   380  
   381  	fmt.Printf("%s\n", data)
   382  	return nil
   383  }
   384  
   385  func commandValidateVersionKeyspace(cmd *cobra.Command, args []string) error {
   386  	cli.FinishedParsing(cmd)
   387  
   388  	ks := cmd.Flags().Arg(0)
   389  	resp, err := client.ValidateVersionKeyspace(commandCtx, &vtctldatapb.ValidateVersionKeyspaceRequest{
   390  		Keyspace: ks,
   391  	})
   392  
   393  	if err != nil {
   394  		return err
   395  	}
   396  
   397  	data, err := cli.MarshalJSON(resp)
   398  	if err != nil {
   399  		return err
   400  	}
   401  
   402  	fmt.Printf("%s\n", data)
   403  	return nil
   404  }
   405  
   406  func init() {
   407  	CreateKeyspace.Flags().BoolVarP(&createKeyspaceOptions.Force, "force", "f", false, "Proceeds even if the keyspace already exists. Does not overwrite the existing keyspace record.")
   408  	CreateKeyspace.Flags().BoolVarP(&createKeyspaceOptions.AllowEmptyVSchema, "allow-empty-vschema", "e", false, "Allows a new keyspace to have no vschema.")
   409  	CreateKeyspace.Flags().Var(&createKeyspaceOptions.ServedFromsMap, "served-from", "Specifies a set of db_type:keyspace pairs used to serve traffic for the keyspace.")
   410  	CreateKeyspace.Flags().Var(&createKeyspaceOptions.KeyspaceType, "type", "The type of the keyspace.")
   411  	CreateKeyspace.Flags().StringVar(&createKeyspaceOptions.BaseKeyspace, "base-keyspace", "", "The base keyspace for a snapshot keyspace.")
   412  	CreateKeyspace.Flags().StringVar(&createKeyspaceOptions.SnapshotTimestamp, "snapshot-timestamp", "", "The snapshot time for a snapshot keyspace, as a timestamp in RFC3339 format.")
   413  	CreateKeyspace.Flags().StringVar(&createKeyspaceOptions.DurabilityPolicy, "durability-policy", "none", "Type of durability to enforce for this keyspace. Default is none. Possible values include 'semi_sync' and others as dictated by registered plugins.")
   414  	Root.AddCommand(CreateKeyspace)
   415  
   416  	DeleteKeyspace.Flags().BoolVarP(&deleteKeyspaceOptions.Recursive, "recursive", "r", false, "Recursively delete all shards in the keyspace, and all tablets in those shards.")
   417  	DeleteKeyspace.Flags().BoolVarP(&deleteKeyspaceOptions.Force, "force", "f", false, "Delete the keyspace even if it cannot be locked; this should only be used for cleanup operations.")
   418  	Root.AddCommand(DeleteKeyspace)
   419  
   420  	Root.AddCommand(FindAllShardsInKeyspace)
   421  	Root.AddCommand(GetKeyspace)
   422  	Root.AddCommand(GetKeyspaces)
   423  
   424  	RemoveKeyspaceCell.Flags().BoolVarP(&removeKeyspaceCellOptions.Force, "force", "f", false, "Proceed even if the cell's topology server cannot be reached. The assumption is that you turned down the entire cell, and just need to update the global topo data.")
   425  	RemoveKeyspaceCell.Flags().BoolVarP(&removeKeyspaceCellOptions.Recursive, "recursive", "r", false, "Also delete all tablets in that cell beloning to the specified keyspace.")
   426  	Root.AddCommand(RemoveKeyspaceCell)
   427  
   428  	SetKeyspaceDurabilityPolicy.Flags().StringVar(&setKeyspaceDurabilityPolicyOptions.DurabilityPolicy, "durability-policy", "none", "Type of durability to enforce for this keyspace. Default is none. Other values include 'semi_sync' and others as dictated by registered plugins.")
   429  	Root.AddCommand(SetKeyspaceDurabilityPolicy)
   430  
   431  	ValidateSchemaKeyspace.Flags().BoolVar(&validateSchemaKeyspaceOptions.IncludeViews, "include-views", false, "Includes views in compared schemas.")
   432  	ValidateSchemaKeyspace.Flags().BoolVar(&validateSchemaKeyspaceOptions.IncludeVSchema, "include-vschema", false, "Includes VSchema validation in validation results.")
   433  	ValidateSchemaKeyspace.Flags().BoolVar(&validateSchemaKeyspaceOptions.SkipNoPrimary, "skip-no-primary", false, "Skips validation on whether or not a primary exists in shards.")
   434  	ValidateSchemaKeyspace.Flags().StringSliceVar(&validateSchemaKeyspaceOptions.ExcludeTables, "exclude-tables", []string{}, "Tables to exclude during schema comparison.")
   435  	Root.AddCommand(ValidateSchemaKeyspace)
   436  
   437  	Root.AddCommand(ValidateVersionKeyspace)
   438  }