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