github.com/pingcap/tiup@v1.15.1/components/cluster/command/scale_out.go (about) 1 // Copyright 2020 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package command 15 16 import ( 17 "os" 18 "path/filepath" 19 20 "github.com/pingcap/tiup/pkg/cluster/manager" 21 operator "github.com/pingcap/tiup/pkg/cluster/operation" 22 "github.com/pingcap/tiup/pkg/cluster/spec" 23 "github.com/pingcap/tiup/pkg/cluster/task" 24 "github.com/pingcap/tiup/pkg/utils" 25 "github.com/spf13/cobra" 26 ) 27 28 func newScaleOutCmd() *cobra.Command { 29 opt := manager.DeployOptions{ 30 IdentityFile: filepath.Join(utils.UserHome(), ".ssh", "id_rsa"), 31 } 32 cmd := &cobra.Command{ 33 Use: "scale-out <cluster-name> [topology.yaml]", 34 Short: "Scale out a TiDB cluster", 35 SilenceUsage: true, 36 RunE: func(cmd *cobra.Command, args []string) error { 37 var ( 38 clusterName string 39 topoFile string 40 ) 41 42 // tiup cluster scale-out --stage1 --stage2 43 // is equivalent to 44 // tiup cluster scale-out 45 if opt.Stage1 && opt.Stage2 { 46 opt.Stage1 = false 47 opt.Stage2 = false 48 } 49 50 if opt.Stage2 && len(args) == 1 { 51 clusterName = args[0] 52 } else { 53 if len(args) != 2 { 54 return cmd.Help() 55 } 56 clusterName = args[0] 57 topoFile = args[1] 58 } 59 60 clusterReport.ID = scrubClusterName(clusterName) 61 teleCommand = append(teleCommand, scrubClusterName(clusterName)) 62 63 // stage2: topoFile is "" 64 if data, err := os.ReadFile(topoFile); err == nil { 65 teleTopology = string(data) 66 } 67 68 return cm.ScaleOut( 69 clusterName, 70 topoFile, 71 postScaleOutHook, 72 final, 73 opt, 74 skipConfirm, 75 gOpt, 76 ) 77 }, 78 ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { 79 switch len(args) { 80 case 0: 81 return shellCompGetClusterName(cm, toComplete) 82 case 1: 83 return nil, cobra.ShellCompDirectiveDefault 84 default: 85 return nil, cobra.ShellCompDirectiveNoFileComp 86 } 87 }, 88 } 89 90 cmd.Flags().StringVarP(&opt.User, "user", "u", utils.CurrentUser(), "The user name to login via SSH. The user must has root (or sudo) privilege.") 91 cmd.Flags().BoolVarP(&opt.SkipCreateUser, "skip-create-user", "", false, "(EXPERIMENTAL) Skip creating the user specified in topology.") 92 cmd.Flags().StringVarP(&opt.IdentityFile, "identity_file", "i", opt.IdentityFile, "The path of the SSH identity file. If specified, public key authentication will be used.") 93 cmd.Flags().BoolVarP(&opt.UsePassword, "password", "p", false, "Use password of target hosts. If specified, password authentication will be used.") 94 cmd.Flags().BoolVarP(&opt.NoLabels, "no-labels", "", false, "Don't check TiKV labels") 95 cmd.Flags().BoolVarP(&opt.Stage1, "stage1", "", false, "Don't start the new instance after scale-out, need to manually execute cluster scale-out --stage2") 96 cmd.Flags().BoolVarP(&opt.Stage2, "stage2", "", false, "Start the new instance and init config after scale-out --stage1") 97 98 return cmd 99 } 100 101 func final(builder *task.Builder, name string, meta spec.Metadata, gOpt operator.Options) { 102 builder.UpdateTopology(name, 103 tidbSpec.Path(name), 104 meta.(*spec.ClusterMeta), 105 nil, /* deleteNodeIds */ 106 ) 107 } 108 109 func postScaleOutHook(builder *task.Builder, newPart spec.Topology, gOpt operator.Options) { 110 postDeployHook(builder, newPart, gOpt) 111 }