Skip to content

Commit

Permalink
Import configuration when migrating a cluster from Ansible (#766)
Browse files Browse the repository at this point in the history
Co-authored-by: SIGSEGV <gnu.crazier@gmail.com>
Co-authored-by: Lonng <heng@lonng.org>
Co-authored-by: Allen Zhong <zhongbenli@pingcap.com>
  • Loading branch information
4 people authored Nov 17, 2020
1 parent eacd119 commit cd971a5
Show file tree
Hide file tree
Showing 12 changed files with 610 additions and 57 deletions.
5 changes: 5 additions & 0 deletions components/cluster/command/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,11 @@ func newImportCmd() *cobra.Command {
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
}
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ require (
gopkg.in/mattn/go-runewidth.v0 v0.0.4 // indirect
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 // indirect
gopkg.in/yaml.v2 v2.2.8
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
honnef.co/go/tools v0.0.1-2020.1.4 // indirect
sigs.k8s.io/yaml v1.2.0 // indirect
software.sslmate.com/src/go-pkcs12 v0.0.0-20200619203921-c9ed90bd32dc
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1194,6 +1194,8 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
Expand Down
165 changes: 160 additions & 5 deletions pkg/cluster/ansible/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@ import (
"io"
"os"
"path/filepath"
"reflect"
"strconv"

"github.com/BurntSushi/toml"
"github.com/pingcap/errors"
"github.com/pingcap/tiup/pkg/cluster/spec"
"github.com/pingcap/tiup/pkg/logger/log"
"github.com/pingcap/tiup/pkg/set"
"github.com/relex/aini"
)

Expand Down Expand Up @@ -81,11 +84,20 @@ func parseInventoryFile(invFile io.Reader) (string, *spec.ClusterMeta, *aini.Inv
clsMeta.Topology.GlobalOptions.DeployDir = grp.Vars["deploy_dir"]
// deploy_dir and data_dir of monitored need to be set, otherwise they will be
// subdirs of deploy_dir in global options
clsMeta.Topology.MonitoredOptions.DeployDir = clsMeta.Topology.GlobalOptions.DeployDir
clsMeta.Topology.MonitoredOptions.DataDir = filepath.Join(
clsMeta.Topology.MonitoredOptions.DeployDir,
"data",
)
allSame := uniqueVar("deploy_dir", inventory.Groups["monitored_servers"].Hosts)
if len(allSame) == 1 {
clsMeta.Topology.MonitoredOptions.DeployDir = allSame[0]
clsMeta.Topology.MonitoredOptions.DataDir = filepath.Join(
clsMeta.Topology.MonitoredOptions.DeployDir,
"data",
)
} else {
clsMeta.Topology.MonitoredOptions.DeployDir = clsMeta.Topology.GlobalOptions.DeployDir
clsMeta.Topology.MonitoredOptions.DataDir = filepath.Join(
clsMeta.Topology.MonitoredOptions.DeployDir,
"data",
)
}

if grp.Vars["process_supervision"] != "systemd" {
return "", nil, inventory, errors.New("only support cluster deployed with systemd")
Expand All @@ -100,6 +112,7 @@ func parseInventoryFile(invFile io.Reader) (string, *spec.ClusterMeta, *aini.Inv
} else {
return "", nil, inventory, errors.New("no available host in the inventory file")
}

return clsName, clsMeta, inventory, err
}

Expand All @@ -113,3 +126,145 @@ func SSHKeyPath() string {

return fmt.Sprintf("%s/.ssh/id_rsa", homeDir)
}

func uniqueVar(key string, hosts map[string]*aini.Host) []string {
vars := set.NewStringSet()
for _, h := range hosts {
vars.Insert(h.Vars[key])
}
return vars.Slice()
}

// parse config files
func parseConfigFile(cfgfile string) (map[string]interface{}, error) {
srvConfigs := make(map[string]interface{})
if _, err := toml.DecodeFile(cfgfile, &srvConfigs); err != nil {
return nil, errors.Annotate(err, "decode toml file")
}
return spec.FlattenMap(srvConfigs), nil
}

func diffConfigs(configs []map[string]interface{}) (global map[string]interface{}, locals []map[string]interface{}) {
global = make(map[string]interface{})
keySet := set.NewStringSet()

// parse all configs from file
for _, config := range configs {
locals = append(locals, config)
for k := range config {
keySet.Insert(k)
}
}

// summary global config
for k := range keySet {
valSet := set.NewAnySet(reflect.DeepEqual)
for _, config := range locals {
valSet.Insert(config[k])
}
if len(valSet.Slice()) > 1 {
// this key can't be put into global
continue
}
global[k] = valSet.Slice()[0]
}

// delete global config from local
for _, config := range locals {
for k := range global {
delete(config, k)
}
}

return
}

// LoadConfig files to clusterMeta, include tidbservers, tikvservers, pdservers pumpservers and drainerservers
func LoadConfig(clsName string, cls *spec.ClusterMeta) error {
// deal with tidb config
configs := []map[string]interface{}{}
for _, srv := range cls.Topology.TiDBServers {
prefixkey := spec.ComponentTiDB
fname := spec.ClusterPath(clsName, spec.AnsibleImportedConfigPath, fmt.Sprintf("%s-%s-%d.toml", prefixkey, srv.Host, srv.Port))
if config, err := parseConfigFile(fname); err == nil {
configs = append(configs, config)
} else {
return err
}
}
global, locals := diffConfigs(configs)
cls.Topology.ServerConfigs.TiDB = global
for i, local := range locals {
cls.Topology.TiDBServers[i].Config = local
}

// deal with tikv config
configs = []map[string]interface{}{}
for _, srv := range cls.Topology.TiKVServers {
prefixkey := spec.ComponentTiKV
fname := spec.ClusterPath(clsName, spec.AnsibleImportedConfigPath, fmt.Sprintf("%s-%s-%d.toml", prefixkey, srv.Host, srv.Port))
if config, err := parseConfigFile(fname); err == nil {
configs = append(configs, config)
} else {
return err
}
}
global, locals = diffConfigs(configs)
cls.Topology.ServerConfigs.TiKV = global
for i, local := range locals {
cls.Topology.TiKVServers[i].Config = local
}

// deal with pd config
configs = []map[string]interface{}{}
for _, srv := range cls.Topology.PDServers {
prefixkey := spec.ComponentPD
fname := spec.ClusterPath(clsName, spec.AnsibleImportedConfigPath, fmt.Sprintf("%s-%s-%d.toml", prefixkey, srv.Host, srv.ClientPort))
if config, err := parseConfigFile(fname); err == nil {
configs = append(configs, config)
} else {
return err
}
}
global, locals = diffConfigs(configs)
cls.Topology.ServerConfigs.PD = global
for i, local := range locals {
cls.Topology.PDServers[i].Config = local
}

// deal with pump config
configs = []map[string]interface{}{}
for _, srv := range cls.Topology.PumpServers {
prefixkey := spec.ComponentPump
fname := spec.ClusterPath(clsName, spec.AnsibleImportedConfigPath, fmt.Sprintf("%s-%s-%d.toml", prefixkey, srv.Host, srv.Port))
if config, err := parseConfigFile(fname); err == nil {
configs = append(configs, config)
} else {
return err
}
}
global, locals = diffConfigs(configs)
cls.Topology.ServerConfigs.Pump = global
for i, local := range locals {
cls.Topology.PumpServers[i].Config = local
}

// deal with drainer config
configs = []map[string]interface{}{}
for _, srv := range cls.Topology.Drainers {
prefixkey := spec.ComponentDrainer
fname := spec.ClusterPath(clsName, spec.AnsibleImportedConfigPath, fmt.Sprintf("%s-%s-%d.toml", prefixkey, srv.Host, srv.Port))
if config, err := parseConfigFile(fname); err == nil {
configs = append(configs, config)
} else {
return err
}
}
global, locals = diffConfigs(configs)
cls.Topology.ServerConfigs.Drainer = global
for i, local := range locals {
cls.Topology.Drainers[i].Config = local
}

return nil
}
Loading

0 comments on commit cd971a5

Please sign in to comment.