github.com/pingcap/tiup@v1.15.1/components/cluster/command/import.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 "context" 18 "fmt" 19 "os" 20 "path/filepath" 21 22 "github.com/fatih/color" 23 "github.com/pingcap/tiup/pkg/cluster/ansible" 24 "github.com/pingcap/tiup/pkg/cluster/ctxt" 25 "github.com/pingcap/tiup/pkg/cluster/spec" 26 "github.com/pingcap/tiup/pkg/tui" 27 "github.com/pingcap/tiup/pkg/utils" 28 "github.com/spf13/cobra" 29 ) 30 31 func newImportCmd() *cobra.Command { 32 var ( 33 ansibleDir string 34 inventoryFileName string 35 ansibleCfgFile string 36 rename string 37 noBackup bool 38 ) 39 40 cmd := &cobra.Command{ 41 Use: "import", 42 Short: "Import an exist TiDB cluster from TiDB-Ansible", 43 RunE: func(cmd *cobra.Command, args []string) error { 44 // Use current directory as ansibleDir by default 45 if ansibleDir == "" { 46 cwd, err := os.Getwd() 47 if err != nil { 48 return err 49 } 50 ansibleDir = cwd 51 } 52 53 ctx := ctxt.New( 54 context.Background(), 55 gOpt.Concurrency, 56 log, 57 ) 58 59 // migrate cluster metadata from Ansible inventory 60 clsName, clsMeta, inv, err := ansible.ReadInventory(ctx, ansibleDir, inventoryFileName) 61 if err != nil { 62 return err 63 } 64 65 // Rename the imported cluster 66 if rename != "" { 67 clsName = rename 68 } 69 if clsName == "" { 70 return fmt.Errorf("cluster name should not be empty") 71 } 72 73 exist, err := tidbSpec.Exist(clsName) 74 if err != nil { 75 return err 76 } 77 78 if exist { 79 return errDeployNameDuplicate. 80 New("Cluster name '%s' is duplicated", clsName). 81 WithProperty(tui.SuggestionFromFormat( 82 fmt.Sprintf("Please use --rename `NAME` to specify another name (You can use `%s list` to see all clusters)", tui.OsArgs0()))) 83 } 84 85 // prompt for backups 86 backupDir := spec.ClusterPath(clsName, "ansible-backup") 87 backupFile := filepath.Join(ansibleDir, fmt.Sprintf("tiup-%s.bak", inventoryFileName)) 88 prompt := fmt.Sprintf("The ansible directory will be moved to %s after import.", backupDir) 89 if noBackup { 90 log.Infof("The '--no-backup' flag is set, the ansible directory will be kept at its current location.") 91 prompt = fmt.Sprintf("The inventory file will be renamed to %s after import.", backupFile) 92 } 93 log.Warnf("TiDB-Ansible and TiUP Cluster can NOT be used together, please DO NOT try to use ansible to manage the imported cluster anymore to avoid metadata conflict.") 94 log.Infof(prompt) 95 if !skipConfirm { 96 err = tui.PromptForConfirmOrAbortError("Do you want to continue? [y/N]: ") 97 if err != nil { 98 return err 99 } 100 } 101 102 if !skipConfirm { 103 err = tui.PromptForConfirmOrAbortError( 104 "Prepared to import TiDB %s cluster %s.\nDo you want to continue? [y/N]:", 105 clsMeta.Version, 106 clsName) 107 if err != nil { 108 return err 109 } 110 } 111 112 // parse config and import nodes 113 if err = ansible.ParseAndImportInventory( 114 ctx, 115 ansibleDir, 116 ansibleCfgFile, 117 clsMeta, 118 inv, 119 gOpt.SSHTimeout, 120 gOpt.SSHType, 121 ); err != nil { 122 return err 123 } 124 125 // copy SSH key to TiUP profile directory 126 if err = utils.MkdirAll(spec.ClusterPath(clsName, "ssh"), 0755); err != nil { 127 return err 128 } 129 srcKeyPathPriv := ansible.SSHKeyPath() 130 srcKeyPathPub := srcKeyPathPriv + ".pub" 131 dstKeyPathPriv := spec.ClusterPath(clsName, "ssh", "id_rsa") 132 dstKeyPathPub := dstKeyPathPriv + ".pub" 133 if err = utils.Copy(srcKeyPathPriv, dstKeyPathPriv); err != nil { 134 return err 135 } 136 if err = utils.Copy(srcKeyPathPub, dstKeyPathPub); err != nil { 137 return err 138 } 139 140 // copy config files form deployment servers 141 if err = ansible.ImportConfig(ctx, clsName, clsMeta, gOpt); err != nil { 142 return err 143 } 144 145 // copy config detail to meta file 146 if err = ansible.LoadConfig(clsName, clsMeta); err != nil { 147 return err 148 } 149 150 if err = spec.SaveClusterMeta(clsName, clsMeta); err != nil { 151 return err 152 } 153 154 // comment config to avoid duplicated copy 155 if err = ansible.CommentConfig(clsName); err != nil { 156 return err 157 } 158 159 // backup ansible files 160 if noBackup { 161 // rename original TiDB-Ansible inventory file 162 if err = utils.Move(filepath.Join(ansibleDir, inventoryFileName), backupFile); err != nil { 163 return err 164 } 165 log.Infof("Ansible inventory renamed to %s.", color.HiCyanString(backupFile)) 166 } else { 167 // move original TiDB-Ansible directory to a staged location 168 if err = utils.Move(ansibleDir, backupDir); err != nil { 169 return err 170 } 171 log.Infof("Ansible inventory saved in %s.", color.HiCyanString(backupDir)) 172 } 173 174 log.Infof("Cluster %s imported.", clsName) 175 fmt.Printf("Try `%s` to show node list and status of the cluster.\n", 176 color.HiYellowString("%s display %s", tui.OsArgs0(), clsName)) 177 return nil 178 }, 179 } 180 181 cmd.Flags().StringVarP(&ansibleDir, "dir", "d", "", "The path to TiDB-Ansible directory") 182 cmd.Flags().StringVar(&inventoryFileName, "inventory", ansible.AnsibleInventoryFile, "The name of inventory file") 183 cmd.Flags().StringVar(&ansibleCfgFile, "ansible-config", ansible.AnsibleConfigFile, "The path to ansible.cfg") 184 cmd.Flags().StringVarP(&rename, "rename", "r", "", "Rename the imported cluster to `NAME`") 185 cmd.Flags().BoolVar(&noBackup, "no-backup", false, "Don't backup ansible dir, useful when there're multiple inventory files") 186 187 return cmd 188 }