github.com/pingcap/tiup@v1.15.1/components/cluster/command/start.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 "database/sql" 18 "fmt" 19 "strings" 20 21 "github.com/fatih/color" 22 "github.com/pingcap/tiup/pkg/cluster/spec" 23 "github.com/pingcap/tiup/pkg/cluster/task" 24 "github.com/pingcap/tiup/pkg/crypto/rand" 25 "github.com/pingcap/tiup/pkg/proxy" 26 "github.com/pingcap/tiup/pkg/utils" 27 "github.com/spf13/cobra" 28 29 // for sql/driver 30 _ "github.com/go-sql-driver/mysql" 31 ) 32 33 func newStartCmd() *cobra.Command { 34 var ( 35 initPasswd bool 36 restoreLeader bool 37 ) 38 39 cmd := &cobra.Command{ 40 Use: "start <cluster-name>", 41 Short: "Start a TiDB cluster", 42 RunE: func(cmd *cobra.Command, args []string) error { 43 if len(args) != 1 { 44 return cmd.Help() 45 } 46 47 if err := validRoles(gOpt.Roles); err != nil { 48 return err 49 } 50 51 clusterName := args[0] 52 clusterReport.ID = scrubClusterName(clusterName) 53 teleCommand = append(teleCommand, scrubClusterName(clusterName)) 54 55 if err := cm.StartCluster(clusterName, gOpt, restoreLeader, func(b *task.Builder, metadata spec.Metadata) { 56 b.UpdateTopology( 57 clusterName, 58 tidbSpec.Path(clusterName), 59 metadata.(*spec.ClusterMeta), 60 nil, /* deleteNodeIds */ 61 ) 62 }); err != nil { 63 return err 64 } 65 66 // init password 67 if initPasswd { 68 pwd, err := initPassword(clusterName) 69 if err != nil { 70 log.Errorf("Failed to set root password of TiDB database to '%s'", pwd) 71 if strings.Contains(strings.ToLower(err.Error()), "error 1045") { 72 log.Errorf("Initializing is only working when the root password is empty") 73 log.Errorf(color.YellowString("Did you already set root password before?")) 74 } 75 return err 76 } 77 log.Warnf("The root password of TiDB database has been changed.") 78 fmt.Printf("The new password is: '%s'.\n", color.HiYellowString(pwd)) // use fmt to avoid printing to audit log 79 log.Warnf("Copy and record it to somewhere safe, %s, and will not be stored.", color.HiRedString("it is only displayed once")) 80 log.Warnf("The generated password %s.", color.HiRedString("can NOT be get and shown again")) 81 } 82 return nil 83 }, 84 ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { 85 switch len(args) { 86 case 0: 87 return shellCompGetClusterName(cm, toComplete) 88 default: 89 return nil, cobra.ShellCompDirectiveNoFileComp 90 } 91 }, 92 } 93 94 cmd.Flags().BoolVar(&initPasswd, "init", false, "Initialize a secure root password for the database") 95 cmd.Flags().BoolVar(&restoreLeader, "restore-leaders", false, "Allow leaders to be scheduled to stores after start") 96 cmd.Flags().StringSliceVarP(&gOpt.Roles, "role", "R", nil, "Only start specified roles") 97 cmd.Flags().StringSliceVarP(&gOpt.Nodes, "node", "N", nil, "Only start specified nodes") 98 99 _ = cmd.Flags().MarkHidden("restore-leaders") 100 101 return cmd 102 } 103 104 func initPassword(clusterName string) (string, error) { 105 metadata, err := spec.ClusterMetadata(clusterName) 106 if err != nil { 107 return "", err 108 } 109 tcpProxy := proxy.GetTCPProxy() 110 111 // generate password 112 pwd, err := rand.Password(18) 113 if err != nil { 114 return pwd, err 115 } 116 117 var lastErr error 118 for _, spec := range metadata.Topology.TiDBServers { 119 spec := spec 120 endpoint := utils.JoinHostPort(spec.Host, spec.Port) 121 if tcpProxy != nil { 122 closeC := tcpProxy.Run([]string{endpoint}) 123 defer tcpProxy.Close(closeC) 124 endpoint = tcpProxy.GetEndpoints()[0] 125 } 126 db, err := createDB(endpoint) 127 if err != nil { 128 lastErr = err 129 continue 130 } 131 defer db.Close() 132 133 sqlStr := fmt.Sprintf("SET PASSWORD FOR 'root'@'%%' = '%s'; FLUSH PRIVILEGES;", pwd) 134 _, err = db.Exec(sqlStr) 135 if err != nil { 136 lastErr = err 137 continue 138 } 139 return pwd, nil 140 } 141 142 return pwd, lastErr 143 } 144 145 func createDB(endpoint string) (db *sql.DB, err error) { 146 dsn := fmt.Sprintf("root:@tcp(%s)/?charset=utf8mb4,utf8&multiStatements=true", endpoint) 147 db, err = sql.Open("mysql", dsn) 148 149 return 150 }