diff --git a/.gitignore b/.gitignore index eccebc3670..8700f03ea4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +vendor/ bin/ *.tar *.gz diff --git a/cmd/root.go b/cmd/root.go index 05be013ea1..31e063125e 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -15,13 +15,12 @@ package cmd import ( "fmt" - "os" - "github.com/fatih/color" "github.com/pingcap-incubator/tiup/pkg/meta" "github.com/pingcap-incubator/tiup/pkg/repository" "github.com/pingcap-incubator/tiup/pkg/version" "github.com/spf13/cobra" + "os" ) var rootCmd *cobra.Command @@ -31,6 +30,7 @@ func init() { var ( binary string + binPath string tag string rm bool repoOpts repository.Options @@ -75,6 +75,7 @@ the latest stable version will be downloaded from the repository. // will be parsed correctly. // e.g: tiup --tag mytag --rm playground --db 3 --pd 3 --kv 4 // => run "playground" with parameters "--db 3 --pd 3 --kv 4" + // tiup --tag mytag --binpath /xxx/tikv-server tikv var transparentParams []string componentSpec := args[0] for i, arg := range os.Args { @@ -83,7 +84,7 @@ the latest stable version will be downloaded from the repository. break } } - return runComponent(tag, componentSpec, transparentParams, rm) + return runComponent(tag, componentSpec, binPath, transparentParams, rm) } return cmd.Help() }, @@ -101,6 +102,7 @@ the latest stable version will be downloaded from the repository. "and the latest version installed will be selected if no version specified") rootCmd.Flags().StringVarP(&tag, "tag", "T", "", "Specify a tag for component instance") rootCmd.Flags().BoolVar(&rm, "rm", false, "Remove the data directory when the component instance finishes its run") + rootCmd.Flags().StringVar(&binPath, "binpath", "", "Specify the binary path of component instance") rootCmd.AddCommand( newInstallCmd(), diff --git a/cmd/run.go b/cmd/run.go index 8b8939fba3..834c6244ca 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -32,7 +32,7 @@ import ( "github.com/pingcap/errors" ) -func runComponent(tag, spec string, args []string, rm bool) error { +func runComponent(tag, spec, binPath string, args []string, rm bool) error { component, version := meta.ParseCompVersion(spec) if !isSupportedComponent(component) { return fmt.Errorf("unkonwn component `%s` (see supported components via `tiup list --refresh`)", component) @@ -41,7 +41,7 @@ func runComponent(tag, spec string, args []string, rm bool) error { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - p, err := launchComponent(ctx, component, version, tag, args) + p, err := launchComponent(ctx, component, version, binPath, tag, args) // If the process has been launched, we must save the process info to meta directory if err == nil || (p != nil && p.Pid != 0) { defer cleanDataDir(rm, p.Dir) @@ -134,19 +134,26 @@ func base62Tag() string { return string(b) } -func launchComponent(ctx context.Context, component string, version repository.Version, tag string, args []string) (*process, error) { - selectVer, err := meta.DownloadComponentIfMissing(component, version) - if err != nil { - return nil, err - } - binPath, err := meta.BinaryPath(component, selectVer) - if err != nil { - return nil, err - } +func launchComponent(ctx context.Context, component string, version repository.Version, binPath string, tag string, args []string) (*process, error) { + var selectVer repository.Version + var installPath string + var err error - installPath, err := meta.ComponentInstalledDir(component, selectVer) - if err != nil { - return nil, err + if binPath == "" { + selectVer, err = meta.DownloadComponentIfMissing(component, version) + if err != nil { + return nil, err + } + + binPath, err = meta.BinaryPath(component, selectVer) + if err != nil { + return nil, err + } + + installPath, err = meta.ComponentInstalledDir(component, selectVer) + if err != nil { + return nil, err + } } wd := os.Getenv(localdata.EnvNameInstanceDataDir) diff --git a/components/playground/instance/instance.go b/components/playground/instance/instance.go index 53c865add2..56b635280f 100644 --- a/components/playground/instance/instance.go +++ b/components/playground/instance/instance.go @@ -31,7 +31,7 @@ type instance struct { // Instance represent running component type Instance interface { Pid() int - Start(ctx context.Context, version repository.Version) error + Start(ctx context.Context, version repository.Version, binPath string) error Wait() error } diff --git a/components/playground/instance/pd.go b/components/playground/instance/pd.go index 0d87b762ba..2d0a5cdfbf 100644 --- a/components/playground/instance/pd.go +++ b/components/playground/instance/pd.go @@ -53,13 +53,14 @@ func (inst *PDInstance) Join(pds []*PDInstance) *PDInstance { } // Start calls set inst.cmd and Start -func (inst *PDInstance) Start(ctx context.Context, version repository.Version) error { +func (inst *PDInstance) Start(ctx context.Context, version repository.Version, binPath string) error { if err := os.MkdirAll(inst.Dir, 0755); err != nil { return err } uid := fmt.Sprintf("pd-%d", inst.ID) args := []string{ - "tiup", compVersion("pd", version), + "tiup", fmt.Sprintf("--binpath=%s", binPath), + compVersion("pd", version), "--name=" + uid, fmt.Sprintf("--data-dir=%s", filepath.Join(inst.Dir, "data")), fmt.Sprintf("--peer-urls=http://%s:%d", inst.Host, inst.Port), diff --git a/components/playground/instance/tidb.go b/components/playground/instance/tidb.go index c8ed5f243e..a122cfa4ed 100644 --- a/components/playground/instance/tidb.go +++ b/components/playground/instance/tidb.go @@ -49,7 +49,7 @@ func NewTiDBInstance(dir, host string, id int, pds []*PDInstance) *TiDBInstance } // Start calls set inst.cmd and Start -func (inst *TiDBInstance) Start(ctx context.Context, version repository.Version) error { +func (inst *TiDBInstance) Start(ctx context.Context, version repository.Version, binPath string) error { if err := os.MkdirAll(inst.Dir, 0755); err != nil { return err } @@ -58,7 +58,8 @@ func (inst *TiDBInstance) Start(ctx context.Context, version repository.Version) endpoints = append(endpoints, fmt.Sprintf("%s:%d", inst.Host, pd.StatusPort)) } args := []string{ - "tiup", compVersion("tidb", version), + "tiup", fmt.Sprintf("--binpath=%s", binPath), + compVersion("tidb", version), "-P", strconv.Itoa(inst.Port), "--store=tikv", fmt.Sprintf("--host=%s", inst.Host), diff --git a/components/playground/instance/tikv.go b/components/playground/instance/tikv.go index 6afdf1c173..0f45aa57dc 100644 --- a/components/playground/instance/tikv.go +++ b/components/playground/instance/tikv.go @@ -50,7 +50,7 @@ func NewTiKVInstance(dir, host string, id int, pds []*PDInstance) *TiKVInstance } // Start calls set inst.cmd and Start -func (inst *TiKVInstance) Start(ctx context.Context, version repository.Version) error { +func (inst *TiKVInstance) Start(ctx context.Context, version repository.Version, binPath string) error { if err := os.MkdirAll(inst.Dir, 0755); err != nil { return err } @@ -69,7 +69,8 @@ func (inst *TiKVInstance) Start(ctx context.Context, version repository.Version) endpoints = append(endpoints, fmt.Sprintf("http://%s:%d", inst.Host, pd.StatusPort)) } inst.cmd = exec.CommandContext(ctx, - "tiup", compVersion("tikv", version), + "tiup", fmt.Sprintf("--binpath=%s", binPath), + compVersion("tikv", version), fmt.Sprintf("--addr=%s:%d", inst.Host, inst.Port), fmt.Sprintf("--status-addr=%s:%d", inst.Host, inst.StatusPort), fmt.Sprintf("--pd=%s", strings.Join(endpoints, ",")), diff --git a/components/playground/main.go b/components/playground/main.go index ff25f628ea..ac718360ed 100644 --- a/components/playground/main.go +++ b/components/playground/main.go @@ -73,6 +73,9 @@ func execute() error { pdNum := 1 host := "127.0.0.1" monitor := false + tidbBinPath := "" + tikvBinPath := "" + pdBinPath := "" rootCmd := &cobra.Command{ Use: "tiup playground [version]", @@ -82,14 +85,15 @@ if you don't specified a version. Examples: $ tiup playground nightly # Start a TiDB nightly version local cluster $ tiup playground v3.0.10 --db 3 --pd 3 --kv 3 # Start a local cluster with 10 nodes - $ tiup playground nightly --monitor # Start a local cluster with monitor system`, + $ tiup playground nightly --monitor # Start a local cluster with monitor system + $ tiup playground --db.binpath /xx/tidb-server # Start a local cluster with component binary path`, SilenceUsage: true, RunE: func(cmd *cobra.Command, args []string) error { version := "" if len(args) > 0 { version = args[0] } - return bootCluster(version, pdNum, tidbNum, tikvNum, host, monitor) + return bootCluster(version, pdNum, tidbNum, tikvNum, host, monitor, tidbBinPath, tikvBinPath, pdBinPath) }, } @@ -98,6 +102,9 @@ Examples: rootCmd.Flags().IntVarP(&pdNum, "pd", "", 1, "PD instance number") rootCmd.Flags().StringVarP(&host, "host", "", host, "Playground cluster host") rootCmd.Flags().BoolVar(&monitor, "monitor", false, "Start prometheus component") + rootCmd.Flags().StringVarP(&tidbBinPath, "db.binpath", "", tidbBinPath, "TiDB instance binary path") + rootCmd.Flags().StringVarP(&tikvBinPath, "kv.binpath", "", tikvBinPath, "TiKV instance binary path") + rootCmd.Flags().StringVarP(&pdBinPath, "pd.binpath", "", pdBinPath, "PD instance binary path") return rootCmd.Execute() } @@ -147,12 +154,30 @@ func hasDashboard(pdAddr string) bool { return false } -func bootCluster(version string, pdNum, tidbNum, tikvNum int, host string, monitor bool) error { +func getAbsolutePath(binPath string) string { + if !strings.HasPrefix(binPath, "/") && !strings.HasPrefix(binPath, "~") { + binPath = filepath.Join(os.Getenv(localdata.EnvNameWorkDir), binPath) + } + return binPath +} + +func bootCluster(version string, pdNum, tidbNum, tikvNum int, host string, monitor bool, tidbBinPath, tikvBinPath, pdBinPath string) error { if pdNum < 1 || tidbNum < 1 || tikvNum < 1 { return fmt.Errorf("all components count must be great than 0 (tidb=%v, tikv=%v, pd=%v)", tidbNum, tikvNum, pdNum) } + var pathMap = make(map[string]string) + if tidbBinPath != "" { + pathMap["tidb"] = getAbsolutePath(tidbBinPath) + } + if tikvBinPath != "" { + pathMap["tikv"] = getAbsolutePath(tikvBinPath) + } + if pdBinPath != "" { + pathMap["pd"] = getAbsolutePath(pdBinPath) + } + // Initialize the profile profileRoot := os.Getenv(localdata.EnvNameHome) if profileRoot == "" { @@ -160,6 +185,9 @@ func bootCluster(version string, pdNum, tidbNum, tikvNum int, host string, monit } profile := localdata.NewProfile(profileRoot) for _, comp := range []string{"pd", "tikv", "tidb"} { + if pathMap[comp] != "" { + continue + } if err := installIfMissing(profile, comp, version); err != nil { return err } @@ -171,6 +199,7 @@ func bootCluster(version string, pdNum, tidbNum, tikvNum int, host string, monit } all := make([]instance.Instance, 0, pdNum+tikvNum+tidbNum) + allRole := make([]string, 0, pdNum+tikvNum+tidbNum) pds := make([]*instance.PDInstance, 0, pdNum) kvs := make([]*instance.TiKVInstance, 0, tikvNum) dbs := make([]*instance.TiDBInstance, 0, tidbNum) @@ -183,6 +212,7 @@ func bootCluster(version string, pdNum, tidbNum, tikvNum int, host string, monit inst := instance.NewPDInstance(dir, host, i) pds = append(pds, inst) all = append(all, inst) + allRole = append(allRole, "pd") } for _, pd := range pds { pd.Join(pds) @@ -193,6 +223,7 @@ func bootCluster(version string, pdNum, tidbNum, tikvNum int, host string, monit inst := instance.NewTiKVInstance(dir, host, i, pds) kvs = append(kvs, inst) all = append(all, inst) + allRole = append(allRole, "tikv") } for i := 0; i < tidbNum; i++ { @@ -200,6 +231,7 @@ func bootCluster(version string, pdNum, tidbNum, tikvNum int, host string, monit inst := instance.NewTiDBInstance(dir, host, i, pds) dbs = append(dbs, inst) all = append(all, inst) + allRole = append(allRole, "tidb") } fmt.Println("Playground Bootstrapping...") @@ -248,8 +280,8 @@ func bootCluster(version string, pdNum, tidbNum, tikvNum int, host string, monit }() } - for _, inst := range all { - if err := inst.Start(ctx, repository.Version(version)); err != nil { + for i, inst := range all { + if err := inst.Start(ctx, repository.Version(version), pathMap[allRole[i]]); err != nil { return err } } diff --git a/tests/expected/tiup/tiup-h.output b/tests/expected/tiup/tiup-h.output index 51042bc86c..591a31d182 100644 --- a/tests/expected/tiup/tiup-h.output +++ b/tests/expected/tiup/tiup-h.output @@ -33,6 +33,7 @@ Available Components: Flags: -B, --binary [:version] Print binary path of a specific version of a component [:version] and the latest version installed will be selected if no version specified + --binpath string Specify the binary path of component instance -h, --help help for tiup --rm Remove the data directory when the component instance finishes its run --skip-version-check Skip the strict version check, by default a version must be a valid SemVer string diff --git a/tests/expected/tiup/tiup-help.output b/tests/expected/tiup/tiup-help.output index eaa3610582..d841e5cde8 100644 --- a/tests/expected/tiup/tiup-help.output +++ b/tests/expected/tiup/tiup-help.output @@ -33,6 +33,7 @@ Available Components: Flags: -B, --binary [:version] Print binary path of a specific version of a component [:version] and the latest version installed will be selected if no version specified + --binpath string Specify the binary path of component instance -h, --help help for tiup --rm Remove the data directory when the component instance finishes its run --skip-version-check Skip the strict version check, by default a version must be a valid SemVer string diff --git a/tests/expected/tiup/tiup.output b/tests/expected/tiup/tiup.output index 51042bc86c..591a31d182 100644 --- a/tests/expected/tiup/tiup.output +++ b/tests/expected/tiup/tiup.output @@ -33,6 +33,7 @@ Available Components: Flags: -B, --binary [:version] Print binary path of a specific version of a component [:version] and the latest version installed will be selected if no version specified + --binpath string Specify the binary path of component instance -h, --help help for tiup --rm Remove the data directory when the component instance finishes its run --skip-version-check Skip the strict version check, by default a version must be a valid SemVer string