diff --git a/Makefile b/Makefile index ed61c18497..fac83dbea7 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,5 @@ -.PHONY: server +.PHONY: cmd components server +.DEFAULT_GOAL := default GOVER := $(shell go version) @@ -24,11 +25,10 @@ FILES := $$(find . -name "*.go") FAILPOINT_ENABLE := $$(tools/bin/failpoint-ctl enable) FAILPOINT_DISABLE := $$(tools/bin/failpoint-ctl disable) -default: build check +default: check build include ./tests/Makefile - # Build TiUP and all components build: tiup components @@ -120,8 +120,6 @@ fmt: @echo "goimports (if installed)" $(shell gimports -w $(FILES) 2>/dev/null) -.PHONY: cmd - tools/bin/errcheck: tools/check/go.mod cd tools/check; \ $(GO) build -o ../bin/errcheck github.com/kisielk/errcheck diff --git a/components/cluster/command/check.go b/components/cluster/command/check.go index 1384ac6da1..c21adca0d6 100644 --- a/components/cluster/command/check.go +++ b/components/cluster/command/check.go @@ -167,6 +167,7 @@ func checkSystemInfo(s *cliutil.SSHConnectionProps, topo *spec.Specification, op inst.OS(), inst.Arch(), insightVer, + "", // use default srcPath inst.GetHost(), task.CheckToolsPathDir, ). diff --git a/components/cluster/command/deploy.go b/components/cluster/command/deploy.go index 3d7bdac836..9d3c82c1aa 100644 --- a/components/cluster/command/deploy.go +++ b/components/cluster/command/deploy.go @@ -146,6 +146,11 @@ func confirmTopology(clusterName, version string, topo *spec.Specification, patc log.Errorf(" 3. The component marked as `patched` has been replaced by previours patch command.") } + if len(topo.TiSparkMasters) > 0 || len(topo.TiSparkWorkers) > 0 { + log.Warnf("There are TiSpark nodes defined in the topology, please note that you'll need to manually install Java Runtime Environment (JRE) 8 on the host, other wise the TiSpark nodes will fail to start.") + log.Warnf("You may read the OpenJDK doc for a reference: https://openjdk.java.net/install/") + } + return cliutil.PromptForConfirmOrAbortError("Do you want to continue? [y/N]: ") } @@ -270,6 +275,7 @@ func deploy(clusterName, clusterVersion, topoFile string, opt deployOptions) err // log dir will always be with values, but might not used by the component logDir := clusterutil.Abs(globalOptions.User, inst.LogDir()) // Deploy component + // prepare deployment server t := task.NewBuilder(). UserSSH(inst.GetHost(), inst.GetSSHPort(), globalOptions.User, gOpt.SSHTimeout). Mkdir(globalOptions.User, inst.GetHost(), @@ -277,30 +283,42 @@ func deploy(clusterName, clusterVersion, topoFile string, opt deployOptions) err filepath.Join(deployDir, "bin"), filepath.Join(deployDir, "conf"), filepath.Join(deployDir, "scripts")). - Mkdir(globalOptions.User, inst.GetHost(), dataDirs...). - CopyComponent( + Mkdir(globalOptions.User, inst.GetHost(), dataDirs...) + + // copy dependency component if needed + switch inst.ComponentName() { + case spec.ComponentTiSpark: + t = t.DeploySpark(inst, version, "" /* default srcPath */, deployDir) + default: + t = t.CopyComponent( inst.ComponentName(), inst.OS(), inst.Arch(), version, + "", // use default srcPath inst.GetHost(), deployDir, - ). - InitConfig( - clusterName, - clusterVersion, - inst, - globalOptions.User, - opt.ignoreConfigCheck, - meta.DirPaths{ - Deploy: deployDir, - Data: dataDirs, - Log: logDir, - Cache: spec.ClusterPath(clusterName, spec.TempConfigPath), - }, - ). - BuildAsStep(fmt.Sprintf(" - Copy %s -> %s", inst.ComponentName(), inst.GetHost())) - deployCompTasks = append(deployCompTasks, t) + ) + } + + // generate configs for the component + t = t.InitConfig( + clusterName, + clusterVersion, + inst, + globalOptions.User, + opt.ignoreConfigCheck, + meta.DirPaths{ + Deploy: deployDir, + Data: dataDirs, + Log: logDir, + Cache: spec.ClusterPath(clusterName, spec.TempConfigPath), + }, + ) + + deployCompTasks = append(deployCompTasks, + t.BuildAsStep(fmt.Sprintf(" - Copy %s -> %s", inst.ComponentName(), inst.GetHost())), + ) }) nodeInfoTask := task.NewBuilder().Func("Check status", func(ctx *task.Context) error { @@ -373,6 +391,11 @@ func buildMonitoredDeployTask( version := spec.ComponentVersion(comp, version) for host, info := range uniqueHosts { + // FIXME: as the uniqueHosts list is built with os-arch as part of the key, + // for platform independent packages, it will be downloaded multiple times + // and be saved with different file names in the packages dir, the tarballs + // are identical and the only difference is platform in filename. + // populate unique os/arch set key := fmt.Sprintf("%s-%s-%s", comp, info.os, info.arch) if _, found := uniqueCompOSArch[key]; !found { @@ -404,6 +427,7 @@ func buildMonitoredDeployTask( info.os, info.arch, version, + "", // use default srcPath host, deployDir, ). diff --git a/components/cluster/command/destroy.go b/components/cluster/command/destroy.go index bd2c8f1d3f..b86f35bca3 100644 --- a/components/cluster/command/destroy.go +++ b/components/cluster/command/destroy.go @@ -69,7 +69,8 @@ You can retain some nodes and roles data when destroy cluster, eg: logger.EnableAuditLog() metadata, err := spec.ClusterMetadata(clusterName) - if err != nil && !errors.Is(perrs.Cause(err), meta.ErrValidate) { + if err != nil && !errors.Is(perrs.Cause(err), meta.ErrValidate) && + !errors.Is(perrs.Cause(err), spec.ErrNoTiSparkMaster) { return err } diff --git a/components/cluster/command/display.go b/components/cluster/command/display.go index fc0f1fd5ce..6fbb7692c0 100644 --- a/components/cluster/command/display.go +++ b/components/cluster/command/display.go @@ -72,7 +72,8 @@ func newDisplayCmd() *cobra.Command { } metadata, err := spec.ClusterMetadata(clusterName) - if err != nil && !errors.Is(perrs.Cause(err), meta.ErrValidate) { + if err != nil && !errors.Is(perrs.Cause(err), meta.ErrValidate) && + !errors.Is(perrs.Cause(err), spec.ErrNoTiSparkMaster) { return perrs.AddStack(err) } return destroyTombstoneIfNeed(clusterName, metadata, gOpt) @@ -88,7 +89,8 @@ func newDisplayCmd() *cobra.Command { func displayDashboardInfo(clusterName string) error { metadata, err := spec.ClusterMetadata(clusterName) - if err != nil && !errors.Is(perrs.Cause(err), meta.ErrValidate) { + if err != nil && !errors.Is(perrs.Cause(err), meta.ErrValidate) && + !errors.Is(perrs.Cause(err), spec.ErrNoTiSparkMaster) { return err } @@ -121,7 +123,8 @@ func displayDashboardInfo(clusterName string) error { func displayClusterMeta(clusterName string, opt *operator.Options) error { clsMeta, err := spec.ClusterMetadata(clusterName) - if err != nil && !errors.Is(perrs.Cause(err), meta.ErrValidate) { + if err != nil && !errors.Is(perrs.Cause(err), meta.ErrValidate) && + !errors.Is(perrs.Cause(err), spec.ErrNoTiSparkMaster) { return err } @@ -175,7 +178,8 @@ func destroyTombstoneIfNeed(clusterName string, metadata *spec.ClusterMeta, opt func displayClusterTopology(clusterName string, opt *operator.Options) error { metadata, err := spec.ClusterMetadata(clusterName) - if err != nil && !errors.Is(perrs.Cause(err), meta.ErrValidate) { + if err != nil && !errors.Is(perrs.Cause(err), meta.ErrValidate) && + !errors.Is(perrs.Cause(err), spec.ErrNoTiSparkMaster) { return err } diff --git a/components/cluster/command/reload.go b/components/cluster/command/reload.go index a0e04010ba..3422d2d681 100644 --- a/components/cluster/command/reload.go +++ b/components/cluster/command/reload.go @@ -112,7 +112,15 @@ func buildReloadTask( case spec.ComponentGrafana, spec.ComponentPrometheus, spec.ComponentAlertManager: version := spec.ComponentVersion(compName, metadata.Version) tb.Download(compName, inst.OS(), inst.Arch(), version). - CopyComponent(compName, inst.OS(), inst.Arch(), version, inst.GetHost(), deployDir) + CopyComponent( + compName, + inst.OS(), + inst.Arch(), + version, + "", // use default srcPath + inst.GetHost(), + deployDir, + ) } hasImported = true } diff --git a/components/cluster/command/scale_in.go b/components/cluster/command/scale_in.go index 8f11409a26..d01db7a968 100644 --- a/components/cluster/command/scale_in.go +++ b/components/cluster/command/scale_in.go @@ -115,7 +115,15 @@ func scaleIn(clusterName string, options operator.Options) error { case spec.ComponentGrafana, spec.ComponentPrometheus, spec.ComponentAlertManager: version := spec.ComponentVersion(compName, metadata.Version) tb.Download(compName, instance.OS(), instance.Arch(), version). - CopyComponent(compName, instance.OS(), instance.Arch(), version, instance.GetHost(), deployDir) + CopyComponent( + compName, + instance.OS(), + instance.Arch(), + version, + "", // use default srcPath + instance.GetHost(), + deployDir, + ) } hasImported = true } diff --git a/components/cluster/command/scale_out.go b/components/cluster/command/scale_out.go index 929a4cbe7c..ae72d34b61 100644 --- a/components/cluster/command/scale_out.go +++ b/components/cluster/command/scale_out.go @@ -15,12 +15,13 @@ package command import ( "context" + "errors" "io/ioutil" "path/filepath" "strings" "github.com/joomcode/errorx" - "github.com/pingcap/errors" + perrs "github.com/pingcap/errors" "github.com/pingcap/tiup/pkg/cliutil" "github.com/pingcap/tiup/pkg/cliutil/prepare" "github.com/pingcap/tiup/pkg/cluster/clusterutil" @@ -72,11 +73,11 @@ func newScaleOutCmd() *cobra.Command { func scaleOut(clusterName, topoFile string, opt scaleOutOptions) error { exist, err := tidbSpec.Exist(clusterName) if err != nil { - return errors.AddStack(err) + return perrs.AddStack(err) } if !exist { - return errors.Errorf("cannot scale-out non-exists cluster %s", clusterName) + return perrs.Errorf("cannot scale-out non-exists cluster %s", clusterName) } metadata, err := spec.ClusterMetadata(clusterName) @@ -91,7 +92,12 @@ func scaleOut(clusterName, topoFile string, opt scaleOutOptions) error { MonitoredOptions: metadata.Topology.MonitoredOptions, ServerConfigs: metadata.Topology.ServerConfigs, } - if err := clusterutil.ParseTopologyYaml(topoFile, &newPart); err != nil { + + // The no tispark master error is ignored, as if the tispark master is removed from the topology + // file for some reason (manual edit, for example), it is still possible to scale-out it to make + // the whole topology back to normal state. + if err := clusterutil.ParseTopologyYaml(topoFile, &newPart); err != nil && + !errors.Is(perrs.Cause(err), spec.ErrNoTiSparkMaster) { return err } @@ -146,7 +152,7 @@ func scaleOut(clusterName, topoFile string, opt scaleOutOptions) error { // FIXME: Map possible task errors and give suggestions. return err } - return errors.Trace(err) + return perrs.Trace(err) } log.Infof("Scaled cluster `%s` out successfully", clusterName) @@ -247,11 +253,28 @@ func buildScaleOutTask( filepath.Join(deployDir, "conf"), filepath.Join(deployDir, "scripts")). Mkdir(metadata.User, inst.GetHost(), dataDirs...) + + srcPath := "" if patchedComponents.Exist(inst.ComponentName()) { - tb.InstallPackage(spec.ClusterPath(clusterName, spec.PatchDirName, inst.ComponentName()+".tar.gz"), inst.GetHost(), deployDir) - } else { - tb.CopyComponent(inst.ComponentName(), inst.OS(), inst.Arch(), version, inst.GetHost(), deployDir) + srcPath = spec.ClusterPath(clusterName, spec.PatchDirName, inst.ComponentName()+".tar.gz") } + + // copy dependency component if needed + switch inst.ComponentName() { + case spec.ComponentTiSpark: + tb = tb.DeploySpark(inst, version, srcPath, deployDir) + default: + tb.CopyComponent( + inst.ComponentName(), + inst.OS(), + inst.Arch(), + version, + srcPath, + inst.GetHost(), + deployDir, + ) + } + t := tb.ScaleConfig(clusterName, metadata.Version, metadata.Topology, @@ -282,7 +305,15 @@ func buildScaleOutTask( case spec.ComponentGrafana, spec.ComponentPrometheus, spec.ComponentAlertManager: version := spec.ComponentVersion(compName, metadata.Version) tb.Download(compName, inst.OS(), inst.Arch(), version). - CopyComponent(compName, inst.OS(), inst.Arch(), version, inst.GetHost(), deployDir) + CopyComponent( + compName, + inst.OS(), + inst.Arch(), + version, + "", // use default srcPath + inst.GetHost(), + deployDir, + ) } hasImported = true } @@ -367,7 +398,7 @@ func validateNewTopo(topo *spec.Specification) (err error) { topo.IterInstance(func(instance spec.Instance) { // check for "imported" parameter, it can not be true when scaling out if instance.IsImported() { - err = errors.New( + err = perrs.New( "'imported' is set to 'true' for new instance, this is only used " + "for instances imported from tidb-ansible and make no sense when " + "scaling out, please delete the line or set it to 'false' for new instances") diff --git a/components/cluster/command/upgrade.go b/components/cluster/command/upgrade.go index 5c87be3884..45152b7216 100644 --- a/components/cluster/command/upgrade.go +++ b/components/cluster/command/upgrade.go @@ -131,16 +131,38 @@ func upgrade(clusterName, clusterVersion string, opt operator.Options) error { if inst.IsImported() { switch inst.ComponentName() { case spec.ComponentPrometheus, spec.ComponentGrafana, spec.ComponentAlertManager: - tb.CopyComponent(inst.ComponentName(), inst.OS(), inst.Arch(), version, inst.GetHost(), deployDir) - default: - tb.BackupComponent(inst.ComponentName(), metadata.Version, inst.GetHost(), deployDir). - CopyComponent(inst.ComponentName(), inst.OS(), inst.Arch(), version, inst.GetHost(), deployDir) + tb.CopyComponent( + inst.ComponentName(), + inst.OS(), + inst.Arch(), + version, + "", // use default srcPath + inst.GetHost(), + deployDir, + ) } hasImported = true - } else { - tb.BackupComponent(inst.ComponentName(), metadata.Version, inst.GetHost(), deployDir). - CopyComponent(inst.ComponentName(), inst.OS(), inst.Arch(), version, inst.GetHost(), deployDir) } + + // backup files of the old version + tb = tb.BackupComponent(inst.ComponentName(), metadata.Version, inst.GetHost(), deployDir) + + // copy dependency component if needed + switch inst.ComponentName() { + case spec.ComponentTiSpark: + tb = tb.DeploySpark(inst, version, "" /* default srcPath */, deployDir) + default: + tb = tb.CopyComponent( + inst.ComponentName(), + inst.OS(), + inst.Arch(), + version, + "", // use default srcPath + inst.GetHost(), + deployDir, + ) + } + tb.InitConfig( clusterName, clusterVersion, diff --git a/components/dm/command/deploy.go b/components/dm/command/deploy.go index 01be7aa97e..469497d2a5 100644 --- a/components/dm/command/deploy.go +++ b/components/dm/command/deploy.go @@ -244,6 +244,7 @@ func deploy(clusterName, clusterVersion, topoFile string, opt deployOptions) err inst.OS(), inst.Arch(), version, + "", // use default srcPath inst.GetHost(), deployDir, ). diff --git a/components/dm/command/scale_out.go b/components/dm/command/scale_out.go index dd76d111fc..6cf2cfac55 100644 --- a/components/dm/command/scale_out.go +++ b/components/dm/command/scale_out.go @@ -234,22 +234,31 @@ func buildScaleOutTask( filepath.Join(deployDir, "conf"), filepath.Join(deployDir, "scripts")). Mkdir(metadata.User, inst.GetHost(), dataDirs...) + + srcPath := "" if patchedComponents.Exist(inst.ComponentName()) { - tb.InstallPackage(meta.ClusterPath(clusterName, meta.PatchDirName, inst.ComponentName()+".tar.gz"), inst.GetHost(), deployDir) - } else { - tb.CopyComponent(inst.ComponentName(), inst.OS(), inst.Arch(), version, inst.GetHost(), deployDir) + srcPath = spec.ClusterPath(clusterName, spec.PatchDirName, inst.ComponentName()+".tar.gz") } - t := tb.ScaleConfig(clusterName, - metadata.Version, - metadata.Topology, - inst, - metadata.User, - meta.DirPaths{ - Deploy: deployDir, - Data: dataDirs, - Log: logDir, - }, - ).Build() + + t := tb.CopyComponent( + inst.ComponentName(), + inst.OS(), + inst.Arch(), + version, + srcPath, + inst.GetHost(), + deployDir, + ).ScaleConfig(clusterName, + metadata.Version, + metadata.Topology, + inst, + metadata.User, + meta.DirPaths{ + Deploy: deployDir, + Data: dataDirs, + Log: logDir, + }, + ).Build() deployCompTasks = append(deployCompTasks, t) }) diff --git a/docker/node/Dockerfile b/docker/node/Dockerfile index 5d0672ab13..249c278792 100644 --- a/docker/node/Dockerfile +++ b/docker/node/Dockerfile @@ -6,14 +6,19 @@ RUN sed -i 's/deb.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list RUN sed -i 's/security.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list # Install packages +# JRE 11 is installed for tispark testing, a tispark node could be started +# with Java 11, but is not going to work properly. However, we don't test +# for SQL in CI, so it's ok to use Java 11 instead of Java 8. RUN apt-get update && \ apt-get -y install \ dos2unix \ openssh-server \ + openjdk-11-jre-headless \ + sudo vim \ && \ -mkdir -p /var/run/sshd && \ -sed -i "s/UsePrivilegeSeparation.*/UsePrivilegeSeparation no/g" /etc/ssh/sshd_config && \ -sed -i "s/PermitRootLogin without-password/PermitRootLogin yes/g" /etc/ssh/sshd_config + mkdir -p /var/run/sshd && \ + sed -i "s/UsePrivilegeSeparation.*/UsePrivilegeSeparation no/g" /etc/ssh/sshd_config && \ + sed -i "s/PermitRootLogin without-password/PermitRootLogin yes/g" /etc/ssh/sshd_config ENV AUTHORIZED_KEYS **None** @@ -22,8 +27,5 @@ ADD run.sh /run.sh RUN dos2unix /run.sh \ && chmod +x /*.sh -# Install deps -RUN apt-get install -qqy sudo vim - EXPOSE 22 CMD ["/run.sh"] diff --git a/examples/topology.example.yaml b/examples/topology.example.yaml index 82163959a8..a302d795ea 100644 --- a/examples/topology.example.yaml +++ b/examples/topology.example.yaml @@ -211,6 +211,28 @@ tiflash_servers: # - host: 10.0.1.21 # - host: 10.0.1.22 +# NOTE: Only 1 master node is supported for now +tispark_masters: + - host: 10.0.1.21 + #spark_config: + # spark.driver.memory: "2g" + # spark.eventLog.enabled: "False" + # spark.tispark.grpc.framesize: 268435456 + # spark.tispark.grpc.timeout_in_sec: 100 + # spark.tispark.meta.reload_period_in_sec: 60 + # spark.tispark.request.command.priority: "Low" + # spark.tispark.table.scan_concurrency: 256 + #spark_env: + # SPARK_EXECUTOR_CORES: 5 + # SPARK_EXECUTOR_MEMORY: "10g" + # SPARK_WORKER_CORES: 5 + # SPARK_WORKER_MEMORY: "10g" + +# NOTE: multiple worker nodes on the same host is not supported +tispark_workers: + - host: 10.0.1.22 + - host: 10.0.1.23 + monitoring_servers: - host: 10.0.1.11 # ssh_port: 22 diff --git a/go.mod b/go.mod index 62d8dfa91d..ccb7d68938 100644 --- a/go.mod +++ b/go.mod @@ -42,7 +42,7 @@ require ( github.com/pingcap/check v0.0.0-20200212061837-5e12011dc712 github.com/pingcap/dm v1.1.0-alpha.0.20200521025928-83063141c5fd github.com/pingcap/errors v0.11.5-0.20190809092503-95897b64e011 - github.com/pingcap/failpoint v0.0.0-20200210140405-f8f9fb234798 + github.com/pingcap/failpoint v0.0.0-20200702092429-9f69995143ce github.com/pingcap/fn v0.0.0-20200306044125-d5540d389059 github.com/pingcap/go-tpc v1.0.4-0.20200525052430-dc963cdeef62 github.com/pingcap/kvproto v0.0.0-20200518112156-d4aeb467de29 diff --git a/go.sum b/go.sum index 191ae884e4..7a4380f694 100644 --- a/go.sum +++ b/go.sum @@ -596,6 +596,8 @@ github.com/pingcap/errors v0.11.5-0.20190809092503-95897b64e011/go.mod h1:Oi8TUi github.com/pingcap/failpoint v0.0.0-20191029060244-12f4ac2fd11d/go.mod h1:DNS3Qg7bEDhU6EXNHF+XSv/PGznQaMJ5FWvctpm6pQI= github.com/pingcap/failpoint v0.0.0-20200210140405-f8f9fb234798 h1:6DMbRqPI1qzQ8N1xc3+nKY8IxSACd9VqQKkRVvbyoIg= github.com/pingcap/failpoint v0.0.0-20200210140405-f8f9fb234798/go.mod h1:DNS3Qg7bEDhU6EXNHF+XSv/PGznQaMJ5FWvctpm6pQI= +github.com/pingcap/failpoint v0.0.0-20200702092429-9f69995143ce h1:Y1kCxlCtlPTMtVcOkjUcuQKh+YrluSo7+7YMCQSzy30= +github.com/pingcap/failpoint v0.0.0-20200702092429-9f69995143ce/go.mod h1:w4PEZ5y16LeofeeGwdgZB4ddv9bLyDuIX+ljstgKZyk= github.com/pingcap/fn v0.0.0-20191016082858-07623b84a47d/go.mod h1:fMRU1BA1y+r89AxUoaAar4JjrhUkVDt0o0Np6V8XbDQ= github.com/pingcap/fn v0.0.0-20200306044125-d5540d389059 h1:Pe2LbxRmbTfAoKJ65bZLmhahmvHm7n9DUxGRQT00208= github.com/pingcap/fn v0.0.0-20200306044125-d5540d389059/go.mod h1:fMRU1BA1y+r89AxUoaAar4JjrhUkVDt0o0Np6V8XbDQ= diff --git a/pkg/cliutil/prepare/prepare.go b/pkg/cliutil/prepare/prepare.go index 86e8c9fee6..cb5e1120bd 100644 --- a/pkg/cliutil/prepare/prepare.go +++ b/pkg/cliutil/prepare/prepare.go @@ -286,6 +286,11 @@ func BuildDownloadCompTasks(version string, instanceIter InstanceIter) []*task.S if _, found := uniqueTaskList[key]; !found { uniqueTaskList[key] = struct{}{} + // download spark as dependency of tispark + if inst.ComponentName() == spec.ComponentTiSpark { + tasks = append(tasks, buildDownloadSparkTask(version, inst)) + } + version := spec.ComponentVersion(inst.ComponentName(), version) t := task.NewBuilder(). Download(inst.ComponentName(), inst.OS(), inst.Arch(), version). @@ -296,3 +301,13 @@ func BuildDownloadCompTasks(version string, instanceIter InstanceIter) []*task.S }) return tasks } + +// buildDownloadSparkTask build download task for spark, which is a dependency of tispark +// FIXME: this is a hack and should be replaced by dependency handling in manifest processing +func buildDownloadSparkTask(version string, inst spec.Instance) *task.StepDisplay { + ver := spec.ComponentVersion(spec.ComponentSpark, version) + return task.NewBuilder(). + Download(spec.ComponentSpark, inst.OS(), inst.Arch(), ver). + BuildAsStep(fmt.Sprintf(" - Download %s:%s (%s/%s)", + spec.ComponentSpark, version, inst.OS(), inst.Arch())) +} diff --git a/pkg/cluster/embed/autogen_pkger.go b/pkg/cluster/embed/autogen_pkger.go index 114c10be1f..0f1596841f 100644 --- a/pkg/cluster/embed/autogen_pkger.go +++ b/pkg/cluster/embed/autogen_pkger.go @@ -22,6 +22,8 @@ func init() { autogenFiles["/templates/config/datasource.yml.tpl"] = "YXBpVmVyc2lvbjogMQpkZWxldGVEYXRhc291cmNlczoKICAtIG5hbWU6IHt7LkNsdXN0ZXJOYW1lfX0KZGF0YXNvdXJjZXM6CiAgLSBuYW1lOiB7ey5DbHVzdGVyTmFtZX19CiAgICB0eXBlOiBwcm9tZXRoZXVzCiAgICBhY2Nlc3M6IHByb3h5CiAgICB1cmw6IGh0dHA6Ly97ey5JUH19Ont7LlBvcnR9fQogICAgd2l0aENyZWRlbnRpYWxzOiBmYWxzZQogICAgaXNEZWZhdWx0OiBmYWxzZQogICAgdGxzQXV0aDogZmFsc2UKICAgIHRsc0F1dGhXaXRoQ0FDZXJ0OiBmYWxzZQogICAgdmVyc2lvbjogMQogICAgZWRpdGFibGU6IHRydWU=" autogenFiles["/templates/config/grafana.ini.tpl"] = "IyMjIyMjIyMjIyMjIyMjIyMjIyMjIEdyYWZhbmEgQ29uZmlndXJhdGlvbiBFeGFtcGxlICMjIyMjIyMjIyMjIyMjIyMjIyMjIwojCiMgRXZlcnl0aGluZyBoYXMgZGVmYXVsdHMgc28geW91IG9ubHkgbmVlZCB0byB1bmNvbW1lbnQgdGhpbmdzIHlvdSB3YW50IHRvCiMgY2hhbmdlCgojIHBvc3NpYmxlIHZhbHVlcyA6IHByb2R1Y3Rpb24sIGRldmVsb3BtZW50CjsgYXBwX21vZGUgPSBwcm9kdWN0aW9uCgojIGluc3RhbmNlIG5hbWUsIGRlZmF1bHRzIHRvIEhPU1ROQU1FIGVudmlyb25tZW50IHZhcmlhYmxlIHZhbHVlIG9yIGhvc3RuYW1lIGlmIEhPU1ROQU1FIHZhciBpcyBlbXB0eQo7IGluc3RhbmNlX25hbWUgPSAke0hPU1ROQU1FfQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIFBhdGhzICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpbcGF0aHNdCiMgUGF0aCB0byB3aGVyZSBncmFmYW5hIGNhbiBzdG9yZSB0ZW1wIGZpbGVzLCBzZXNzaW9ucywgYW5kIHRoZSBzcWxpdGUzIGRiIChpZiB0aGF0IGlzIHVzZWQpCiMKZGF0YSA9IHt7LkRlcGxveURpcn19L2RhdGEKIwojIERpcmVjdG9yeSB3aGVyZSBncmFmYW5hIGNhbiBzdG9yZSBsb2dzCiMKbG9ncyA9IHt7LkRlcGxveURpcn19L2xvZ3MKIwojIERpcmVjdG9yeSB3aGVyZSBncmFmYW5hIHdpbGwgYXV0b21hdGljYWxseSBzY2FuIGFuZCBsb29rIGZvciBwbHVnaW5zCiMKcGx1Z2lucyA9IHt7LkRlcGxveURpcn19L3BsdWdpbnMKIwojIGZvbGRlciB0aGF0IGNvbnRhaW5zIHByb3Zpc2lvbmluZyBjb25maWcgZmlsZXMgdGhhdCBncmFmYW5hIHdpbGwgYXBwbHkgb24gc3RhcnR1cCBhbmQgd2hpbGUgcnVubmluZy4KcHJvdmlzaW9uaW5nID0ge3suRGVwbG95RGlyfX0vcHJvdmlzaW9uaW5nCgojCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyBTZXJ2ZXIgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCltzZXJ2ZXJdCiMgUHJvdG9jb2wgKGh0dHAgb3IgaHR0cHMpCjtwcm90b2NvbCA9IGh0dHAKCiMgVGhlIGlwIGFkZHJlc3MgdG8gYmluZCB0bywgZW1wdHkgd2lsbCBiaW5kIHRvIGFsbCBpbnRlcmZhY2VzCjtodHRwX2FkZHIgPQoKIyBUaGUgaHR0cCBwb3J0ICB0byB1c2UKaHR0cF9wb3J0ID0ge3suUG9ydH19CgojIFRoZSBwdWJsaWMgZmFjaW5nIGRvbWFpbiBuYW1lIHVzZWQgdG8gYWNjZXNzIGdyYWZhbmEgZnJvbSBhIGJyb3dzZXIKZG9tYWluID0ge3suSVB9fQoKIyBSZWRpcmVjdCB0byBjb3JyZWN0IGRvbWFpbiBpZiBob3N0IGhlYWRlciBkb2VzIG5vdCBtYXRjaCBkb21haW4KIyBQcmV2ZW50cyBETlMgcmViaW5kaW5nIGF0dGFja3MKO2VuZm9yY2VfZG9tYWluID0gZmFsc2UKCiMgVGhlIGZ1bGwgcHVibGljIGZhY2luZyB1cmwKO3Jvb3RfdXJsID0gJShwcm90b2NvbClzOi8vJShkb21haW4pczolKGh0dHBfcG9ydClzLwoKIyBMb2cgd2ViIHJlcXVlc3RzCjtyb3V0ZXJfbG9nZ2luZyA9IGZhbHNlCgojIHRoZSBwYXRoIHJlbGF0aXZlIHdvcmtpbmcgcGF0aAo7c3RhdGljX3Jvb3RfcGF0aCA9IHB1YmxpYwoKIyBlbmFibGUgZ3ppcAo7ZW5hYmxlX2d6aXAgPSBmYWxzZQoKIyBodHRwcyBjZXJ0cyAmIGtleSBmaWxlCjtjZXJ0X2ZpbGUgPQo7Y2VydF9rZXkgPQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIERhdGFiYXNlICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpbZGF0YWJhc2VdCiMgRWl0aGVyICJteXNxbCIsICJwb3N0Z3JlcyIgb3IgInNxbGl0ZTMiLCBpdCdzIHlvdXIgY2hvaWNlCjt0eXBlID0gc3FsaXRlMwo7aG9zdCA9IDEyNy4wLjAuMTozMzA2CjtuYW1lID0gZ3JhZmFuYQo7dXNlciA9IHJvb3QKO3Bhc3N3b3JkID0KCiMgRm9yICJwb3N0Z3JlcyIgb25seSwgZWl0aGVyICJkaXNhYmxlIiwgInJlcXVpcmUiIG9yICJ2ZXJpZnktZnVsbCIKO3NzbF9tb2RlID0gZGlzYWJsZQoKIyBGb3IgInNxbGl0ZTMiIG9ubHksIHBhdGggcmVsYXRpdmUgdG8gZGF0YV9wYXRoIHNldHRpbmcKO3BhdGggPSBncmFmYW5hLmRiCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMgU2Vzc2lvbiAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKW3Nlc3Npb25dCiMgRWl0aGVyICJtZW1vcnkiLCAiZmlsZSIsICJyZWRpcyIsICJteXNxbCIsICJwb3N0Z3JlcyIsIGRlZmF1bHQgaXMgImZpbGUiCjtwcm92aWRlciA9IGZpbGUKCiMgUHJvdmlkZXIgY29uZmlnIG9wdGlvbnMKIyBtZW1vcnk6IG5vdCBoYXZlIGFueSBjb25maWcgeWV0CiMgZmlsZTogc2Vzc2lvbiBkaXIgcGF0aCwgaXMgcmVsYXRpdmUgdG8gZ3JhZmFuYSBkYXRhX3BhdGgKIyByZWRpczogY29uZmlnIGxpa2UgcmVkaXMgc2VydmVyIGUuZy4gYGFkZHI9MTI3LjAuMC4xOjYzNzkscG9vbF9zaXplPTEwMCxkYj1ncmFmYW5hYAojIG15c3FsOiBnby1zcWwtZHJpdmVyL215c3FsIGRzbiBjb25maWcgc3RyaW5nLCBlLmcuIGB1c2VyOnBhc3N3b3JkQHRjcCgxMjcuMC4wLjE6MzMwNikvZGF0YWJhc2VfbmFtZWAKIyBwb3N0Z3JlczogdXNlcj1hIHBhc3N3b3JkPWIgaG9zdD1sb2NhbGhvc3QgcG9ydD01NDMyIGRibmFtZT1jIHNzbG1vZGU9ZGlzYWJsZQo7cHJvdmlkZXJfY29uZmlnID0gc2Vzc2lvbnMKCiMgU2Vzc2lvbiBjb29raWUgbmFtZQo7Y29va2llX25hbWUgPSBncmFmYW5hX3Nlc3MKCiMgSWYgeW91IHVzZSBzZXNzaW9uIGluIGh0dHBzIG9ubHksIGRlZmF1bHQgaXMgZmFsc2UKO2Nvb2tpZV9zZWN1cmUgPSBmYWxzZQoKIyBTZXNzaW9uIGxpZmUgdGltZSwgZGVmYXVsdCBpcyA4NjQwMAo7c2Vzc2lvbl9saWZlX3RpbWUgPSA4NjQwMAoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIEFuYWx5dGljcyAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKW2FuYWx5dGljc10KIyBTZXJ2ZXIgcmVwb3J0aW5nLCBzZW5kcyB1c2FnZSBjb3VudGVycyB0byBzdGF0cy5ncmFmYW5hLm9yZyBldmVyeSAyNCBob3Vycy4KIyBObyBpcCBhZGRyZXNzZXMgYXJlIGJlaW5nIHRyYWNrZWQsIG9ubHkgc2ltcGxlIGNvdW50ZXJzIHRvIHRyYWNrCiMgcnVubmluZyBpbnN0YW5jZXMsIGRhc2hib2FyZCBhbmQgZXJyb3IgY291bnRzLiBJdCBpcyB2ZXJ5IGhlbHBmdWwgdG8gdXMuCiMgQ2hhbmdlIHRoaXMgb3B0aW9uIHRvIGZhbHNlIHRvIGRpc2FibGUgcmVwb3J0aW5nLgo7cmVwb3J0aW5nX2VuYWJsZWQgPSB0cnVlCgojIFNldCB0byBmYWxzZSB0byBkaXNhYmxlIGFsbCBjaGVja3MgdG8gaHR0cHM6Ly9ncmFmYW5hLm5ldAojIGZvciBuZXcgdmVzaW9ucyAoZ3JhZmFuYSBpdHNlbGYgYW5kIHBsdWdpbnMpLCBjaGVjayBpcyB1c2VkCiMgaW4gc29tZSBVSSB2aWV3cyB0byBub3RpZnkgdGhhdCBncmFmYW5hIG9yIHBsdWdpbiB1cGRhdGUgZXhpc3RzCiMgVGhpcyBvcHRpb24gZG9lcyBub3QgY2F1c2UgYW55IGF1dG8gdXBkYXRlcywgbm9yIHNlbmQgYW55IGluZm9ybWF0aW9uCiMgb25seSBhIEdFVCByZXF1ZXN0IHRvIGh0dHA6Ly9ncmFmYW5hLm5ldCB0byBnZXQgbGF0ZXN0IHZlcnNpb25zCmNoZWNrX2Zvcl91cGRhdGVzID0gdHJ1ZQoKIyBHb29nbGUgQW5hbHl0aWNzIHVuaXZlcnNhbCB0cmFja2luZyBjb2RlLCBvbmx5IGVuYWJsZWQgaWYgeW91IHNwZWNpZnkgYW4gaWQgaGVyZQo7Z29vZ2xlX2FuYWx5dGljc191YV9pZCA9CgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMgU2VjdXJpdHkgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCltzZWN1cml0eV0KIyBkZWZhdWx0IGFkbWluIHVzZXIsIGNyZWF0ZWQgb24gc3RhcnR1cAo7YWRtaW5fdXNlciA9IGFkbWluCgojIGRlZmF1bHQgYWRtaW4gcGFzc3dvcmQsIGNhbiBiZSBjaGFuZ2VkIGJlZm9yZSBmaXJzdCBzdGFydCBvZiBncmFmYW5hLCAgb3IgaW4gcHJvZmlsZSBzZXR0aW5ncwo7YWRtaW5fcGFzc3dvcmQgPSBhZG1pbgoKIyB1c2VkIGZvciBzaWduaW5nCjtzZWNyZXRfa2V5ID0gU1cyWWN3VEliOXpwT09ob1BzTW0KCiMgQXV0by1sb2dpbiByZW1lbWJlciBkYXlzCjtsb2dpbl9yZW1lbWJlcl9kYXlzID0gNwo7Y29va2llX3VzZXJuYW1lID0gZ3JhZmFuYV91c2VyCjtjb29raWVfcmVtZW1iZXJfbmFtZSA9IGdyYWZhbmFfcmVtZW1iZXIKCiMgZGlzYWJsZSBncmF2YXRhciBwcm9maWxlIGltYWdlcwo7ZGlzYWJsZV9ncmF2YXRhciA9IGZhbHNlCgojIGRhdGEgc291cmNlIHByb3h5IHdoaXRlbGlzdCAoaXBfb3JfZG9tYWluOnBvcnQgc2VwYXJhdGVkIGJ5IHNwYWNlcykKO2RhdGFfc291cmNlX3Byb3h5X3doaXRlbGlzdCA9Cgpbc25hcHNob3RzXQojIHNuYXBzaG90IHNoYXJpbmcgb3B0aW9ucwo7ZXh0ZXJuYWxfZW5hYmxlZCA9IHRydWUKO2V4dGVybmFsX3NuYXBzaG90X3VybCA9IGh0dHBzOi8vc25hcHNob3RzLW9yaWdpbi5yYWludGFuay5pbwo7ZXh0ZXJuYWxfc25hcHNob3RfbmFtZSA9IFB1Ymxpc2ggdG8gc25hcHNob3QucmFpbnRhbmsuaW8KCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyBVc2VycyAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKW3VzZXJzXQojIGRpc2FibGUgdXNlciBzaWdudXAgLyByZWdpc3RyYXRpb24KO2FsbG93X3NpZ25fdXAgPSB0cnVlCgojIEFsbG93IG5vbiBhZG1pbiB1c2VycyB0byBjcmVhdGUgb3JnYW5pemF0aW9ucwo7YWxsb3dfb3JnX2NyZWF0ZSA9IHRydWUKCiMgU2V0IHRvIHRydWUgdG8gYXV0b21hdGljYWxseSBhc3NpZ24gbmV3IHVzZXJzIHRvIHRoZSBkZWZhdWx0IG9yZ2FuaXphdGlvbiAoaWQgMSkKO2F1dG9fYXNzaWduX29yZyA9IHRydWUKCiMgRGVmYXVsdCByb2xlIG5ldyB1c2VycyB3aWxsIGJlIGF1dG9tYXRpY2FsbHkgYXNzaWduZWQgKGlmIGRpc2FibGVkIGFib3ZlIGlzIHNldCB0byB0cnVlKQo7YXV0b19hc3NpZ25fb3JnX3JvbGUgPSBWaWV3ZXIKCiMgQmFja2dyb3VuZCB0ZXh0IGZvciB0aGUgdXNlciBmaWVsZCBvbiB0aGUgbG9naW4gcGFnZQo7bG9naW5faGludCA9IGVtYWlsIG9yIHVzZXJuYW1lCgojIERlZmF1bHQgVUkgdGhlbWUgKCJkYXJrIiBvciAibGlnaHQiKQo7ZGVmYXVsdF90aGVtZSA9IGRhcmsKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyBBbm9ueW1vdXMgQXV0aCAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpbYXV0aC5hbm9ueW1vdXNdCiMgZW5hYmxlIGFub255bW91cyBhY2Nlc3MKO2VuYWJsZWQgPSBmYWxzZQoKIyBzcGVjaWZ5IG9yZ2FuaXphdGlvbiBuYW1lIHRoYXQgc2hvdWxkIGJlIHVzZWQgZm9yIHVuYXV0aGVudGljYXRlZCB1c2Vycwo7b3JnX25hbWUgPSBNYWluIE9yZy4KCiMgc3BlY2lmeSByb2xlIGZvciB1bmF1dGhlbnRpY2F0ZWQgdXNlcnMKO29yZ19yb2xlID0gVmlld2VyCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMgQmFzaWMgQXV0aCAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpbYXV0aC5iYXNpY10KO2VuYWJsZWQgPSB0cnVlCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMgQXV0aCBMREFQICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjClthdXRoLmxkYXBdCjtlbmFibGVkID0gZmFsc2UKO2NvbmZpZ19maWxlID0gL2V0Yy9ncmFmYW5hL2xkYXAudG9tbAoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIFNNVFAgLyBFbWFpbGluZyAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpbc210cF0KO2VuYWJsZWQgPSBmYWxzZQo7aG9zdCA9IGxvY2FsaG9zdDoyNQo7dXNlciA9CjtwYXNzd29yZCA9CjtjZXJ0X2ZpbGUgPQo7a2V5X2ZpbGUgPQo7c2tpcF92ZXJpZnkgPSBmYWxzZQo7ZnJvbV9hZGRyZXNzID0gYWRtaW5AZ3JhZmFuYS5sb2NhbGhvc3QKCltlbWFpbHNdCjt3ZWxjb21lX2VtYWlsX29uX3NpZ25fdXAgPSBmYWxzZQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIExvZ2dpbmcgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKW2xvZ10KIyBFaXRoZXIgImNvbnNvbGUiLCAiZmlsZSIsICJzeXNsb2ciLiBEZWZhdWx0IGlzIGNvbnNvbGUgYW5kICBmaWxlCiMgVXNlIHNwYWNlIHRvIHNlcGFyYXRlIG11bHRpcGxlIG1vZGVzLCBlLmcuICJjb25zb2xlIGZpbGUiCm1vZGUgPSBmaWxlCgojIEVpdGhlciAidHJhY2UiLCAiZGVidWciLCAiaW5mbyIsICJ3YXJuIiwgImVycm9yIiwgImNyaXRpY2FsIiwgZGVmYXVsdCBpcyAiaW5mbyIKO2xldmVsID0gaW5mbwoKIyBGb3IgImNvbnNvbGUiIG1vZGUgb25seQpbbG9nLmNvbnNvbGVdCjtsZXZlbCA9CgojIGxvZyBsaW5lIGZvcm1hdCwgdmFsaWQgb3B0aW9ucyBhcmUgdGV4dCwgY29uc29sZSBhbmQganNvbgo7Zm9ybWF0ID0gY29uc29sZQoKIyBGb3IgImZpbGUiIG1vZGUgb25seQpbbG9nLmZpbGVdCmxldmVsID0gaW5mbwoKIyBsb2cgbGluZSBmb3JtYXQsIHZhbGlkIG9wdGlvbnMgYXJlIHRleHQsIGNvbnNvbGUgYW5kIGpzb24KZm9ybWF0ID0gdGV4dAoKIyBUaGlzIGVuYWJsZXMgYXV0b21hdGVkIGxvZyByb3RhdGUoc3dpdGNoIG9mIGZvbGxvd2luZyBvcHRpb25zKSwgZGVmYXVsdCBpcyB0cnVlCjtsb2dfcm90YXRlID0gdHJ1ZQoKIyBNYXggbGluZSBudW1iZXIgb2Ygc2luZ2xlIGZpbGUsIGRlZmF1bHQgaXMgMTAwMDAwMAo7bWF4X2xpbmVzID0gMTAwMDAwMAoKIyBNYXggc2l6ZSBzaGlmdCBvZiBzaW5nbGUgZmlsZSwgZGVmYXVsdCBpcyAyOCBtZWFucyAxIDw8IDI4LCAyNTZNQgo7bWF4X3NpemVfc2hpZnQgPSAyOAoKIyBTZWdtZW50IGxvZyBkYWlseSwgZGVmYXVsdCBpcyB0cnVlCjtkYWlseV9yb3RhdGUgPSB0cnVlCgojIEV4cGlyZWQgZGF5cyBvZiBsb2cgZmlsZShkZWxldGUgYWZ0ZXIgbWF4IGRheXMpLCBkZWZhdWx0IGlzIDcKO21heF9kYXlzID0gNwoKW2xvZy5zeXNsb2ddCjtsZXZlbCA9CgojIGxvZyBsaW5lIGZvcm1hdCwgdmFsaWQgb3B0aW9ucyBhcmUgdGV4dCwgY29uc29sZSBhbmQganNvbgo7Zm9ybWF0ID0gdGV4dAoKIyBTeXNsb2cgbmV0d29yayB0eXBlIGFuZCBhZGRyZXNzLiBUaGlzIGNhbiBiZSB1ZHAsIHRjcCwgb3IgdW5peC4gSWYgbGVmdCBibGFuaywgdGhlIGRlZmF1bHQgdW5peCBlbmRwb2ludHMgd2lsbCBiZSB1c2VkLgo7bmV0d29yayA9CjthZGRyZXNzID0KCiMgU3lzbG9nIGZhY2lsaXR5LiB1c2VyLCBkYWVtb24gYW5kIGxvY2FsMCB0aHJvdWdoIGxvY2FsNyBhcmUgdmFsaWQuCjtmYWNpbGl0eSA9CgojIFN5c2xvZyB0YWcuIEJ5IGRlZmF1bHQsIHRoZSBwcm9jZXNzJyBhcmd2WzBdIGlzIHVzZWQuCjt0YWcgPQoKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyBBTVFQIEV2ZW50IFB1Ymxpc2hlciAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpbZXZlbnRfcHVibGlzaGVyXQo7ZW5hYmxlZCA9IGZhbHNlCjtyYWJiaXRtcV91cmwgPSBhbXFwOi8vbG9jYWxob3N0Lwo7ZXhjaGFuZ2UgPSBncmFmYW5hX2V2ZW50cwoKOyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyBEYXNoYm9hcmQgSlNPTiBmaWxlcyAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpbZGFzaGJvYXJkcy5qc29uXQplbmFibGVkID0gZmFsc2UKcGF0aCA9IHt7LkRlcGxveURpcn19L2Rhc2hib2FyZHMKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyBJbnRlcm5hbCBHcmFmYW5hIE1ldHJpY3MgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBNZXRyaWNzIGF2YWlsYWJsZSBhdCBIVFRQIEFQSSBVcmwgL2FwaS9tZXRyaWNzClttZXRyaWNzXQojIERpc2FibGUgLyBFbmFibGUgaW50ZXJuYWwgbWV0cmljcwo7ZW5hYmxlZCAgICAgICAgICAgPSB0cnVlCgojIFB1Ymxpc2ggaW50ZXJ2YWwKO2ludGVydmFsX3NlY29uZHMgID0gMTAKCiMgU2VuZCBpbnRlcm5hbCBtZXRyaWNzIHRvIEdyYXBoaXRlCjsgW21ldHJpY3MuZ3JhcGhpdGVdCjsgYWRkcmVzcyA9IGxvY2FsaG9zdDoyMDAzCjsgcHJlZml4ID0gcHJvZC5ncmFmYW5hLiUoaW5zdGFuY2VfbmFtZSlzLgoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIEludGVybmFsIEdyYWZhbmEgTWV0cmljcyAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIFVybCB1c2VkIHRvIHRvIGltcG9ydCBkYXNoYm9hcmRzIGRpcmVjdGx5IGZyb20gR3JhZmFuYS5uZXQKW2dyYWZhbmFfbmV0XQp1cmwgPSBodHRwczovL2dyYWZhbmEubmV0" autogenFiles["/templates/config/prometheus.yml.tpl"] = "LS0tCmdsb2JhbDoKICBzY3JhcGVfaW50ZXJ2YWw6ICAgICAxNXMgIyBCeSBkZWZhdWx0LCBzY3JhcGUgdGFyZ2V0cyBldmVyeSAxNSBzZWNvbmRzLgogIGV2YWx1YXRpb25faW50ZXJ2YWw6IDE1cyAjIEJ5IGRlZmF1bHQsIHNjcmFwZSB0YXJnZXRzIGV2ZXJ5IDE1IHNlY29uZHMuCiAgIyBzY3JhcGVfdGltZW91dCBpcyBzZXQgdG8gdGhlIGdsb2JhbCBkZWZhdWx0ICgxMHMpLgogIGV4dGVybmFsX2xhYmVsczoKICAgIGNsdXN0ZXI6ICd7ey5DbHVzdGVyTmFtZX19JwogICAgbW9uaXRvcjogInByb21ldGhldXMiCgojIExvYWQgYW5kIGV2YWx1YXRlIHJ1bGVzIGluIHRoaXMgZmlsZSBldmVyeSAnZXZhbHVhdGlvbl9pbnRlcnZhbCcgc2Vjb25kcy4KcnVsZV9maWxlczoKICAtICdub2RlLnJ1bGVzLnltbCcKICAtICdibGFja2VyLnJ1bGVzLnltbCcKICAtICdieXBhc3MucnVsZXMueW1sJwogIC0gJ3BkLnJ1bGVzLnltbCcKICAtICd0aWRiLnJ1bGVzLnltbCcKICAtICd0aWt2LnJ1bGVzLnltbCcKICAtICd0aWt2LmFjY2VsZXJhdGUucnVsZXMueW1sJwp7ey0gaWYgLlRpRmxhc2hTdGF0dXNBZGRyc319CiAgLSAndGlmbGFzaC5ydWxlcy55bWwnCnt7LSBlbmR9fQp7ey0gaWYgLlB1bXBBZGRyc319CiAgLSAnYmlubG9nLnJ1bGVzLnltbCcKe3stIGVuZH19Cnt7LSBpZiAuQ0RDQWRkcnN9fQogIC0gJ3RpY2RjLnJ1bGVzLnltbCcKe3stIGVuZH19Cnt7LSBpZiAuS2Fma2FBZGRyc319CiAgLSAna2Fma2EucnVsZXMueW1sJwp7ey0gZW5kfX0Ke3stIGlmIC5MaWdodG5pbmdBZGRyc319CiAgLSAnbGlnaHRuaW5nLnJ1bGVzLnltbCcKe3stIGVuZH19Cgp7ey0gaWYgLkFsZXJ0bWFuYWdlckFkZHJzfX0KYWxlcnRpbmc6CiBhbGVydG1hbmFnZXJzOgogLSBzdGF0aWNfY29uZmlnczoKICAgLSB0YXJnZXRzOgp7ey0gcmFuZ2UgLkFsZXJ0bWFuYWdlckFkZHJzfX0KICAgICAtICd7ey59fScKe3stIGVuZH19Cnt7LSBlbmR9fQoKc2NyYXBlX2NvbmZpZ3M6Cnt7LSBpZiAuUHVzaGdhdGV3YXlBZGRyfX0KICAtIGpvYl9uYW1lOiAnb3ZlcndyaXR0ZW4tY2x1c3RlcicKICAgIHNjcmFwZV9pbnRlcnZhbDogMTVzCiAgICBob25vcl9sYWJlbHM6IHRydWUgIyBkb24ndCBvdmVyd3JpdGUgam9iICYgaW5zdGFuY2UgbGFiZWxzCiAgICBzdGF0aWNfY29uZmlnczoKICAgICAgLSB0YXJnZXRzOiBbJ3t7LlB1c2hnYXRld2F5QWRkcn19J10KCiAgLSBqb2JfbmFtZTogImJsYWNrYm94X2V4cG9ydGVyX2h0dHAiCiAgICBzY3JhcGVfaW50ZXJ2YWw6IDMwcwogICAgbWV0cmljc19wYXRoOiAvcHJvYmUKICAgIHBhcmFtczoKICAgICAgbW9kdWxlOiBbaHR0cF8yeHhdCiAgICBzdGF0aWNfY29uZmlnczoKICAgIC0gdGFyZ2V0czoKICAgICAgLSAnaHR0cDovL3t7LlB1c2hnYXRld2F5QWRkcn19L21ldHJpY3MnCiAgICByZWxhYmVsX2NvbmZpZ3M6CiAgICAgIC0gc291cmNlX2xhYmVsczogW19fYWRkcmVzc19fXQogICAgICAgIHRhcmdldF9sYWJlbDogX19wYXJhbV90YXJnZXQKICAgICAgLSBzb3VyY2VfbGFiZWxzOiBbX19wYXJhbV90YXJnZXRdCiAgICAgICAgdGFyZ2V0X2xhYmVsOiBpbnN0YW5jZQogICAgICAtIHRhcmdldF9sYWJlbDogX19hZGRyZXNzX18KICAgICAgICByZXBsYWNlbWVudDoge3suQmxhY2tib3hBZGRyfX0Ke3stIGVuZH19Cnt7LSBpZiAuTGlnaHRuaW5nQWRkcnN9fQogIC0gam9iX25hbWU6ICJsaWdodG5pbmciCiAgICBzdGF0aWNfY29uZmlnczoKICAgICAgLSB0YXJnZXRzOiBbJ3t7aW5kZXggLkxpZ2h0bmluZ0FkZHJzIDB9fSddCnt7LSBlbmR9fQogIC0gam9iX25hbWU6ICJvdmVyd3JpdHRlbi1ub2RlcyIKICAgIGhvbm9yX2xhYmVsczogdHJ1ZSAjIGRvbid0IG92ZXJ3cml0ZSBqb2IgJiBpbnN0YW5jZSBsYWJlbHMKICAgIHN0YXRpY19jb25maWdzOgogICAgLSB0YXJnZXRzOgp7ey0gcmFuZ2UgLk5vZGVFeHBvcnRlckFkZHJzfX0KICAgICAgLSAne3sufX0nCnt7LSBlbmR9fQogIC0gam9iX25hbWU6ICJ0aWRiIgogICAgaG9ub3JfbGFiZWxzOiB0cnVlICMgZG9uJ3Qgb3ZlcndyaXRlIGpvYiAmIGluc3RhbmNlIGxhYmVscwogICAgc3RhdGljX2NvbmZpZ3M6CiAgICAtIHRhcmdldHM6Cnt7LSByYW5nZSAuVGlEQlN0YXR1c0FkZHJzfX0KICAgICAgLSAne3sufX0nCnt7LSBlbmR9fQogIC0gam9iX25hbWU6ICJ0aWt2IgogICAgaG9ub3JfbGFiZWxzOiB0cnVlICMgZG9uJ3Qgb3ZlcndyaXRlIGpvYiAmIGluc3RhbmNlIGxhYmVscwogICAgc3RhdGljX2NvbmZpZ3M6CiAgICAtIHRhcmdldHM6Cnt7LSByYW5nZSAuVGlLVlN0YXR1c0FkZHJzfX0KICAgICAgLSAne3sufX0nCnt7LSBlbmR9fQogIC0gam9iX25hbWU6ICJwZCIKICAgIGhvbm9yX2xhYmVsczogdHJ1ZSAjIGRvbid0IG92ZXJ3cml0ZSBqb2IgJiBpbnN0YW5jZSBsYWJlbHMKICAgIHN0YXRpY19jb25maWdzOgogICAgLSB0YXJnZXRzOgp7ey0gcmFuZ2UgLlBEQWRkcnN9fQogICAgICAtICd7ey59fScKe3stIGVuZH19Cnt7LSBpZiAuVGlGbGFzaFN0YXR1c0FkZHJzfX0KICAtIGpvYl9uYW1lOiAidGlmbGFzaCIKICAgIGhvbm9yX2xhYmVsczogdHJ1ZSAjIGRvbid0IG92ZXJ3cml0ZSBqb2IgJiBpbnN0YW5jZSBsYWJlbHMKICAgIHN0YXRpY19jb25maWdzOgogICAgLSB0YXJnZXRzOgogICAge3stIHJhbmdlIC5UaUZsYXNoU3RhdHVzQWRkcnN9fQogICAgICAgLSAne3sufX0nCiAgICB7ey0gZW5kfX0KICAgIHt7LSByYW5nZSAuVGlGbGFzaExlYXJuZXJTdGF0dXNBZGRyc319CiAgICAgICAtICd7ey59fScKICAgIHt7LSBlbmR9fQp7ey0gZW5kfX0Ke3stIGlmIC5QdW1wQWRkcnN9fQp7ey0gaWYgLkthZmthRXhwb3J0ZXJBZGRyfX0KICAtIGpvYl9uYW1lOiAna2Fma2FfZXhwb3J0ZXInCiAgICBob25vcl9sYWJlbHM6IHRydWUgIyBkb24ndCBvdmVyd3JpdGUgam9iICYgaW5zdGFuY2UgbGFiZWxzCiAgICBzdGF0aWNfY29uZmlnczoKICAgIC0gdGFyZ2V0czoKICAgICAgLSAne3suS2Fma2FFeHBvcnRlckFkZHJ9fScKe3stIGVuZH19CiAgLSBqb2JfbmFtZTogJ3B1bXAnCiAgICBob25vcl9sYWJlbHM6IHRydWUgIyBkb24ndCBvdmVyd3JpdGUgam9iICYgaW5zdGFuY2UgbGFiZWxzCiAgICBzdGF0aWNfY29uZmlnczoKICAgIC0gdGFyZ2V0czoKICAgIHt7LSByYW5nZSAuUHVtcEFkZHJzfX0KICAgICAgLSAne3sufX0nCiAgICB7ey0gZW5kfX0KICAtIGpvYl9uYW1lOiAnZHJhaW5lcicKICAgIGhvbm9yX2xhYmVsczogdHJ1ZSAjIGRvbid0IG92ZXJ3cml0ZSBqb2IgJiBpbnN0YW5jZSBsYWJlbHMKICAgIHN0YXRpY19jb25maWdzOgogICAgLSB0YXJnZXRzOgogICAge3stIHJhbmdlIC5EcmFpbmVyQWRkcnN9fQogICAgICAtICd7ey59fScKICAgIHt7LSBlbmR9fQogIC0gam9iX25hbWU6ICJwb3J0X3Byb2JlIgogICAgc2NyYXBlX2ludGVydmFsOiAzMHMKICAgIG1ldHJpY3NfcGF0aDogL3Byb2JlCiAgICBwYXJhbXM6CiAgICAgIG1vZHVsZTogW3RjcF9jb25uZWN0XQogICAgc3RhdGljX2NvbmZpZ3M6Cnt7LSBpZiAuS2Fma2FBZGRyc319CiAgICAtIHRhcmdldHM6CiAgICB7ey0gcmFuZ2UgLkthZmthQWRkcnN9fQogICAgICAgIC0gJ3t7Ln19JwogICAge3stIGVuZH19CiAgICAgIGxhYmVsczoKICAgICAgICBncm91cDogJ2thZmthJwp7ey0gZW5kfX0Ke3stIGlmIC5ab29rZWVwZXJBZGRyc319CiAgICAtIHRhcmdldHM6CiAgICB7ey0gcmFuZ2UgLlpvb2tlZXBlckFkZHJzfX0KICAgICAgLSAne3sufX0nCiAgICB7ey0gZW5kfX0KICAgICAgbGFiZWxzOgogICAgICAgIGdyb3VwOiAnem9va2VlcGVyJwp7ey0gZW5kfX0KICAgIC0gdGFyZ2V0czoKe3stIHJhbmdlIC5QdW1wQWRkcnN9fQogICAgICAtICd7ey59fScKe3stIGVuZH19CiAgICAgIGxhYmVsczoKICAgICAgICBncm91cDogJ3B1bXAnCiAgICAtIHRhcmdldHM6CiAgICB7ey0gcmFuZ2UgLkRyYWluZXJBZGRyc319CiAgICAgIC0gJ3t7Ln19JwogICAge3stIGVuZH19CiAgICAgIGxhYmVsczoKICAgICAgICBncm91cDogJ2RyYWluZXInCnt7LSBpZiAuS2Fma2FFeHBvcnRlckFkZHJ9fQogICAgLSB0YXJnZXRzOgogICAgICAtICd7ey5LYWZrYUV4cG9ydGVyQWRkcn19JwogICAgICBsYWJlbHM6CiAgICAgICAgZ3JvdXA6ICdrYWZrYV9leHBvcnRlcicKe3stIGVuZH19CiAgICByZWxhYmVsX2NvbmZpZ3M6CiAgICAgIC0gc291cmNlX2xhYmVsczogW19fYWRkcmVzc19fXQogICAgICAgIHRhcmdldF9sYWJlbDogX19wYXJhbV90YXJnZXQKICAgICAgLSBzb3VyY2VfbGFiZWxzOiBbX19wYXJhbV90YXJnZXRdCiAgICAgICAgdGFyZ2V0X2xhYmVsOiBpbnN0YW5jZQogICAgICAtIHRhcmdldF9sYWJlbDogX19hZGRyZXNzX18KICAgICAgICByZXBsYWNlbWVudDoge3suQmxhY2tib3hBZGRyfX0Ke3stIGVuZH19Cnt7LSBpZiAuQ0RDQWRkcnN9fQogIC0gam9iX25hbWU6ICJ0aWNkYyIKICAgIGhvbm9yX2xhYmVsczogdHJ1ZSAjIGRvbid0IG92ZXJ3cml0ZSBqb2IgJiBpbnN0YW5jZSBsYWJlbHMKICAgIHN0YXRpY19jb25maWdzOgogICAgLSB0YXJnZXRzOgp7ey0gcmFuZ2UgLkNEQ0FkZHJzfX0KICAgICAgLSAne3sufX0nCnt7LSBlbmR9fQp7ey0gZW5kfX0KICAtIGpvYl9uYW1lOiAidGlkYl9wb3J0X3Byb2JlIgogICAgc2NyYXBlX2ludGVydmFsOiAzMHMKICAgIG1ldHJpY3NfcGF0aDogL3Byb2JlCiAgICBwYXJhbXM6CiAgICAgIG1vZHVsZTogW3RjcF9jb25uZWN0XQogICAgc3RhdGljX2NvbmZpZ3M6CiAgICAtIHRhcmdldHM6CiAgICB7ey0gcmFuZ2UgLlRpREJTdGF0dXNBZGRyc319CiAgICAgIC0gJ3t7Ln19JyAKICAgIHt7LSBlbmR9fQogICAgICBsYWJlbHM6CiAgICAgICAgZ3JvdXA6ICd0aWRiJwogICAgLSB0YXJnZXRzOgogICAge3stIHJhbmdlIC5UaUtWU3RhdHVzQWRkcnN9fQogICAgICAtICd7ey59fScKICAgIHt7LSBlbmR9fQogICAgICBsYWJlbHM6CiAgICAgICAgZ3JvdXA6ICd0aWt2JwogICAgLSB0YXJnZXRzOgogICAge3stIHJhbmdlIC5QREFkZHJzfX0KICAgICAgLSAne3sufX0nCiAgICB7ey0gZW5kfX0KICAgICAgbGFiZWxzOgogICAgICAgIGdyb3VwOiAncGQnCnt7LSBpZiAuVGlGbGFzaFN0YXR1c0FkZHJzfX0KICAgIC0gdGFyZ2V0czoKICAgIHt7LSByYW5nZSAuVGlGbGFzaFN0YXR1c0FkZHJzfX0KICAgICAgIC0gJ3t7Ln19JwogICAge3stIGVuZH19CiAgICAgIGxhYmVsczoKICAgICAgICBncm91cDogJ3RpZmxhc2gnCnt7LSBlbmR9fQp7ey0gaWYgLlB1c2hnYXRld2F5QWRkcn19CiAgICAtIHRhcmdldHM6CiAgICAgIC0gJ3t7LlB1c2hnYXRld2F5QWRkcn19JwogICAgICBsYWJlbHM6CiAgICAgICAgZ3JvdXA6ICdwdXNoZ2F0ZXdheScKe3stIGVuZH19Cnt7LSBpZiAuR3JhZmFuYUFkZHJ9fQogICAgLSB0YXJnZXRzOgogICAgICAtICd7ey5HcmFmYW5hQWRkcn19JwogICAgICBsYWJlbHM6CiAgICAgICAgZ3JvdXA6ICdncmFmYW5hJwp7ey0gZW5kfX0KICAgIC0gdGFyZ2V0czoKICAgIHt7LSByYW5nZSAuTm9kZUV4cG9ydGVyQWRkcnN9fQogICAgICAtICd7ey59fScKICAgIHt7LSBlbmR9fQogICAgICBsYWJlbHM6CiAgICAgICAgZ3JvdXA6ICdub2RlX2V4cG9ydGVyJwogICAgLSB0YXJnZXRzOgogICAge3stIHJhbmdlIC5CbGFja2JveEV4cG9ydGVyQWRkcnN9fQogICAgICAtICd7ey59fScKICAgIHt7LSBlbmR9fQogICAgICBsYWJlbHM6CiAgICAgICAgZ3JvdXA6ICdibGFja2JveF9leHBvcnRlcicKICAgIHJlbGFiZWxfY29uZmlnczoKICAgICAgLSBzb3VyY2VfbGFiZWxzOiBbX19hZGRyZXNzX19dCiAgICAgICAgdGFyZ2V0X2xhYmVsOiBfX3BhcmFtX3RhcmdldAogICAgICAtIHNvdXJjZV9sYWJlbHM6IFtfX3BhcmFtX3RhcmdldF0KICAgICAgICB0YXJnZXRfbGFiZWw6IGluc3RhbmNlCiAgICAgIC0gdGFyZ2V0X2xhYmVsOiBfX2FkZHJlc3NfXwogICAgICAgIHJlcGxhY2VtZW50OiB7ey5CbGFja2JveEFkZHJ9fQp7ey0gcmFuZ2UgJGFkZHIgOj0gLkJsYWNrYm94RXhwb3J0ZXJBZGRyc319CiAgLSBqb2JfbmFtZTogImJsYWNrYm94X2V4cG9ydGVyX3t7JGFkZHJ9fV9pY21wIgogICAgc2NyYXBlX2ludGVydmFsOiA2cwogICAgbWV0cmljc19wYXRoOiAvcHJvYmUKICAgIHBhcmFtczoKICAgICAgbW9kdWxlOiBbaWNtcF0KICAgIHN0YXRpY19jb25maWdzOgogICAgLSB0YXJnZXRzOgogICAge3stIHJhbmdlICQuTW9uaXRvcmVkU2VydmVyc319CiAgICAgIC0gJ3t7Ln19JwogICAge3stIGVuZH19CiAgICByZWxhYmVsX2NvbmZpZ3M6CiAgICAgIC0gc291cmNlX2xhYmVsczogW19fYWRkcmVzc19fXQogICAgICAgIHJlZ2V4OiAoLiopKDo4MCk/CiAgICAgICAgdGFyZ2V0X2xhYmVsOiBfX3BhcmFtX3RhcmdldAogICAgICAgIHJlcGxhY2VtZW50OiAkezF9CiAgICAgIC0gc291cmNlX2xhYmVsczogW19fcGFyYW1fdGFyZ2V0XQogICAgICAgIHJlZ2V4OiAoLiopCiAgICAgICAgdGFyZ2V0X2xhYmVsOiBwaW5nCiAgICAgICAgcmVwbGFjZW1lbnQ6ICR7MX0KICAgICAgLSBzb3VyY2VfbGFiZWxzOiBbXQogICAgICAgIHJlZ2V4OiAuKgogICAgICAgIHRhcmdldF9sYWJlbDogX19hZGRyZXNzX18KICAgICAgICByZXBsYWNlbWVudDoge3skYWRkcn19Cnt7LSBlbmR9fQ==" + autogenFiles["/templates/config/spark-defaults.conf.tpl"] = "IwojIExpY2Vuc2VkIHRvIHRoZSBBcGFjaGUgU29mdHdhcmUgRm91bmRhdGlvbiAoQVNGKSB1bmRlciBvbmUgb3IgbW9yZQojIGNvbnRyaWJ1dG9yIGxpY2Vuc2UgYWdyZWVtZW50cy4gIFNlZSB0aGUgTk9USUNFIGZpbGUgZGlzdHJpYnV0ZWQgd2l0aAojIHRoaXMgd29yayBmb3IgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiByZWdhcmRpbmcgY29weXJpZ2h0IG93bmVyc2hpcC4KIyBUaGUgQVNGIGxpY2Vuc2VzIHRoaXMgZmlsZSB0byBZb3UgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMAojICh0aGUgIkxpY2Vuc2UiKTsgeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoCiMgdGhlIExpY2Vuc2UuICBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXQKIwojICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAojCiMgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQojIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuICJBUyBJUyIgQkFTSVMsCiMgV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuCiMgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAojIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLgojCgojIERlZmF1bHQgc3lzdGVtIHByb3BlcnRpZXMgaW5jbHVkZWQgd2hlbiBydW5uaW5nIHNwYXJrLXN1Ym1pdC4KIyBUaGlzIGlzIHVzZWZ1bCBmb3Igc2V0dGluZyBkZWZhdWx0IGVudmlyb25tZW50YWwgc2V0dGluZ3MuCgojIEV4YW1wbGU6CiNzcGFyay5ldmVudExvZy5kaXI6ICJoZGZzOi8vbmFtZW5vZGU6ODAyMS9kaXJlY3RvcnkiCiMgc3BhcmsuZXhlY3V0b3IuZXh0cmFKYXZhT3B0aW9ucyAgLVhYOitQcmludEdDRGV0YWlscyAtRGtleT12YWx1ZSAtRG51bWJlcnM9Im9uZSB0d28gdGhyZWUiCgp7ey0gZGVmaW5lICJQRExpc3QifX0KICB7ey0gcmFuZ2UgJGlkeCwgJHBkIDo9IC59fQogICAge3stIGlmIGVxICRpZHggMH19CiAgICAgIHt7LSAkcGR9fQogICAge3stIGVsc2UgLX19CiAgICAgICx7eyRwZH19CiAgICB7ey0gZW5kfX0KICB7ey0gZW5kfX0Ke3stIGVuZH19Cgp7eyByYW5nZSAkaywgJHYgOj0gLkN1c3RvbUZpZWxkc319Cnt7ICRrIH19ICAge3sgJHYgfX0Ke3stIGVuZCB9fQpzcGFyay5zcWwuZXh0ZW5zaW9ucyAgIG9yZy5hcGFjaGUuc3Bhcmsuc3FsLlRpRXh0ZW5zaW9ucwoKe3stIGlmIC5UaVNwYXJrTWFzdGVyc319CnNwYXJrLm1hc3RlciAgIHNwYXJrOi8ve3suVGlTcGFya01hc3RlcnN9fQp7ey0gZW5kfX0KCnNwYXJrLnRpc3BhcmsucGQuYWRkcmVzc2VzIHt7dGVtcGxhdGUgIlBETGlzdCIgLkVuZHBvaW50c319Cg==" + autogenFiles["/templates/config/spark-log4j.properties.tpl"] = "IwojIExpY2Vuc2VkIHRvIHRoZSBBcGFjaGUgU29mdHdhcmUgRm91bmRhdGlvbiAoQVNGKSB1bmRlciBvbmUgb3IgbW9yZQojIGNvbnRyaWJ1dG9yIGxpY2Vuc2UgYWdyZWVtZW50cy4gIFNlZSB0aGUgTk9USUNFIGZpbGUgZGlzdHJpYnV0ZWQgd2l0aAojIHRoaXMgd29yayBmb3IgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiByZWdhcmRpbmcgY29weXJpZ2h0IG93bmVyc2hpcC4KIyBUaGUgQVNGIGxpY2Vuc2VzIHRoaXMgZmlsZSB0byBZb3UgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMAojICh0aGUgIkxpY2Vuc2UiKTsgeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoCiMgdGhlIExpY2Vuc2UuICBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXQKIwojICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAojCiMgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQojIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuICJBUyBJUyIgQkFTSVMsCiMgV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuCiMgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAojIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLgojCgojIFNldCBldmVyeXRoaW5nIHRvIGJlIGxvZ2dlZCB0byB0aGUgY29uc29sZQpsb2c0ai5yb290Q2F0ZWdvcnk9SU5GTywgY29uc29sZQpsb2c0ai5hcHBlbmRlci5jb25zb2xlPW9yZy5hcGFjaGUubG9nNGouQ29uc29sZUFwcGVuZGVyCmxvZzRqLmFwcGVuZGVyLmNvbnNvbGUudGFyZ2V0PVN5c3RlbS5lcnIKbG9nNGouYXBwZW5kZXIuY29uc29sZS5sYXlvdXQ9b3JnLmFwYWNoZS5sb2c0ai5QYXR0ZXJuTGF5b3V0CmxvZzRqLmFwcGVuZGVyLmNvbnNvbGUubGF5b3V0LkNvbnZlcnNpb25QYXR0ZXJuPSVke3l5L01NL2RkIEhIOm1tOnNzfSAlcCAlY3sxfTogJW0lbgoKIyBTZXQgdGhlIGRlZmF1bHQgc3Bhcmstc2hlbGwgbG9nIGxldmVsIHRvIFdBUk4uIFdoZW4gcnVubmluZyB0aGUgc3Bhcmstc2hlbGwsIHRoZQojIGxvZyBsZXZlbCBmb3IgdGhpcyBjbGFzcyBpcyB1c2VkIHRvIG92ZXJ3cml0ZSB0aGUgcm9vdCBsb2dnZXIncyBsb2cgbGV2ZWwsIHNvIHRoYXQKIyB0aGUgdXNlciBjYW4gaGF2ZSBkaWZmZXJlbnQgZGVmYXVsdHMgZm9yIHRoZSBzaGVsbCBhbmQgcmVndWxhciBTcGFyayBhcHBzLgpsb2c0ai5sb2dnZXIub3JnLmFwYWNoZS5zcGFyay5yZXBsLk1haW49V0FSTgoKIyBTZXR0aW5ncyB0byBxdWlldCB0aGlyZCBwYXJ0eSBsb2dzIHRoYXQgYXJlIHRvbyB2ZXJib3NlCmxvZzRqLmxvZ2dlci5vcmcuc3BhcmtfcHJvamVjdC5qZXR0eT1XQVJOCmxvZzRqLmxvZ2dlci5vcmcuc3BhcmtfcHJvamVjdC5qZXR0eS51dGlsLmNvbXBvbmVudC5BYnN0cmFjdExpZmVDeWNsZT1FUlJPUgpsb2c0ai5sb2dnZXIub3JnLmFwYWNoZS5zcGFyay5yZXBsLlNwYXJrSU1haW4kZXhwclR5cGVyPUlORk8KbG9nNGoubG9nZ2VyLm9yZy5hcGFjaGUuc3BhcmsucmVwbC5TcGFya0lMb29wJFNwYXJrSUxvb3BJbnRlcnByZXRlcj1JTkZPCmxvZzRqLmxvZ2dlci5vcmcuYXBhY2hlLnBhcnF1ZXQ9RVJST1IKbG9nNGoubG9nZ2VyLnBhcnF1ZXQ9RVJST1IKCiMgU1BBUkstOTE4MzogU2V0dGluZ3MgdG8gYXZvaWQgYW5ub3lpbmcgbWVzc2FnZXMgd2hlbiBsb29raW5nIHVwIG5vbmV4aXN0ZW50IFVERnMgaW4gU3BhcmtTUUwgd2l0aCBIaXZlIHN1cHBvcnQKbG9nNGoubG9nZ2VyLm9yZy5hcGFjaGUuaGFkb29wLmhpdmUubWV0YXN0b3JlLlJldHJ5aW5nSE1TSGFuZGxlcj1GQVRBTApsb2c0ai5sb2dnZXIub3JnLmFwYWNoZS5oYWRvb3AuaGl2ZS5xbC5leGVjLkZ1bmN0aW9uUmVnaXN0cnk9RVJST1IKCiMgdGlzcGFyayBkaXNhYmxlICJXQVJOIE9iamVjdFN0b3JlOjU2OCAtIEZhaWxlZCB0byBnZXQgZGF0YWJhc2UiCmxvZzRqLmxvZ2dlci5vcmcuYXBhY2hlLmhhZG9vcC5oaXZlLm1ldGFzdG9yZS5PYmplY3RTdG9yZT1FUlJPUgo=" autogenFiles["/templates/scripts/run_alertmanager.sh.tpl"] = "IyEvYmluL2Jhc2gKc2V0IC1lCgpERVBMT1lfRElSPXt7LkRlcGxveURpcn19CmNkICIke0RFUExPWV9ESVJ9IiB8fCBleGl0IDEKCiMgV0FSTklORzogVGhpcyBmaWxlIHdhcyBhdXRvLWdlbmVyYXRlZC4gRG8gbm90IGVkaXQhCiMgICAgICAgICAgQWxsIHlvdXIgZWRpdCBtaWdodCBiZSBvdmVyd3JpdHRlbiEKCmV4ZWMgPiA+KHRlZSAtaSAtYSAie3suTG9nRGlyfX0vYWxlcnRtYW5hZ2VyLmxvZyIpCmV4ZWMgMj4mMQoKe3stIGlmIC5OdW1hTm9kZX19CmV4ZWMgbnVtYWN0bCAtLWNwdW5vZGViaW5kPXt7Lk51bWFOb2RlfX0gLS1tZW1iaW5kPXt7Lk51bWFOb2RlfX0gYmluL2FsZXJ0bWFuYWdlciBcCnt7LSBlbHNlfX0KZXhlYyBiaW4vYWxlcnRtYW5hZ2VyL2FsZXJ0bWFuYWdlciBcCnt7LSBlbmR9fQogICAgLS1jb25maWcuZmlsZT0iY29uZi9hbGVydG1hbmFnZXIueW1sIiBcCiAgICAtLXN0b3JhZ2UucGF0aD0ie3suRGF0YURpcn19IiBcCiAgICAtLWRhdGEucmV0ZW50aW9uPTEyMGggXAogICAgLS1sb2cubGV2ZWw9ImluZm8iIFwKICAgIC0td2ViLmxpc3Rlbi1hZGRyZXNzPSJ7ey5JUH19Ont7LldlYlBvcnR9fSIgXAp7ey0gaWYgLkVuZFBvaW50c319Cnt7LSByYW5nZSAkaWR4LCAkYW0gOj0gLkVuZFBvaW50c319CiAgICAtLWNsdXN0ZXIucGVlcj0ie3skYW0uSVB9fTp7eyRhbS5DbHVzdGVyUG9ydH19IiBcCnt7LSBlbmR9fQp7ey0gZW5kfX0KICAgIC0tY2x1c3Rlci5saXN0ZW4tYWRkcmVzcz0ie3suSVB9fTp7ey5DbHVzdGVyUG9ydH19Igo=" autogenFiles["/templates/scripts/run_blackbox_exporter.sh.tpl"] = "IyEvYmluL2Jhc2gKc2V0IC1lCgojIFdBUk5JTkc6IFRoaXMgZmlsZSB3YXMgYXV0by1nZW5lcmF0ZWQuIERvIG5vdCBlZGl0IQojICAgICAgICAgIEFsbCB5b3VyIGVkaXQgbWlnaHQgYmUgb3ZlcndyaXR0ZW4hCkRFUExPWV9ESVI9e3suRGVwbG95RGlyfX0KY2QgIiR7REVQTE9ZX0RJUn0iIHx8IGV4aXQgMQoKZXhlYyA+ID4odGVlIC1pIC1hICJ7ey5Mb2dEaXJ9fS9ibGFja2JveF9leHBvcnRlci5sb2ciKQpleGVjIDI+JjEKCnt7LSBpZiAuTnVtYU5vZGV9fQpleGVjIG51bWFjdGwgLS1jcHVub2RlYmluZD17ey5OdW1hTm9kZX19IC0tbWVtYmluZD17ey5OdW1hTm9kZX19IGJpbi9ibGFja2JveF9leHBvcnRlci9ibGFja2JveF9leHBvcnRlciBcCnt7LSBlbHNlfX0KZXhlYyBiaW4vYmxhY2tib3hfZXhwb3J0ZXIvYmxhY2tib3hfZXhwb3J0ZXIgXAp7ey0gZW5kfX0KICAgIC0td2ViLmxpc3Rlbi1hZGRyZXNzPSI6e3suUG9ydH19IiBcCiAgICAtLWxvZy5sZXZlbD0iaW5mbyIgXAogICAgLS1jb25maWcuZmlsZT0iY29uZi9ibGFja2JveC55bWwiCg==" autogenFiles["/templates/scripts/run_cdc.sh.tpl"] = "IyEvYmluL2Jhc2gKc2V0IC1lCgojIFdBUk5JTkc6IFRoaXMgZmlsZSB3YXMgYXV0by1nZW5lcmF0ZWQuIERvIG5vdCBlZGl0IQojICAgICAgICAgIEFsbCB5b3VyIGVkaXQgbWlnaHQgYmUgb3ZlcndyaXR0ZW4hCkRFUExPWV9ESVI9e3suRGVwbG95RGlyfX0KY2QgIiR7REVQTE9ZX0RJUn0iIHx8IGV4aXQgMQoKe3stIGRlZmluZSAiUERMaXN0In19CiAge3stIHJhbmdlICRpZHgsICRwZCA6PSAufX0KICAgIHt7LSBpZiBlcSAkaWR4IDB9fQogICAgICB7ey0gJHBkLlNjaGVtZX19Oi8ve3skcGQuSVB9fTp7eyRwZC5DbGllbnRQb3J0fX0KICAgIHt7LSBlbHNlIC19fQogICAgICAse3stICRwZC5TY2hlbWV9fTovL3t7JHBkLklQfX06e3skcGQuQ2xpZW50UG9ydH19CiAgICB7ey0gZW5kfX0KICB7ey0gZW5kfX0Ke3stIGVuZH19Cgp7ey0gaWYgLk51bWFOb2RlfX0KZXhlYyBudW1hY3RsIC0tY3B1bm9kZWJpbmQ9e3suTnVtYU5vZGV9fSAtLW1lbWJpbmQ9e3suTnVtYU5vZGV9fSBiaW4vY2RjIHNlcnZlciBcCnt7LSBlbHNlfX0KZXhlYyBiaW4vY2RjIHNlcnZlciBcCnt7LSBlbmR9fQogICAgLS1hZGRyICIwLjAuMC4wOnt7LlBvcnR9fSIgXAogICAgLS1hZHZlcnRpc2UtYWRkciAie3suSVB9fTp7ey5Qb3J0fX0iIFwKICAgIC0tcGQgInt7dGVtcGxhdGUgIlBETGlzdCIgLkVuZHBvaW50c319IiBcCiAgICAtLWxvZy1maWxlICJ7ey5Mb2dEaXJ9fS9jZGMubG9nIiAyPj4gInt7LkxvZ0Rpcn19L2NkY19zdGRlcnIubG9nIgo=" @@ -39,5 +41,8 @@ func init() { autogenFiles["/templates/scripts/run_tidb.sh.tpl"] = "IyEvYmluL2Jhc2gKc2V0IC1lCgojIFdBUk5JTkc6IFRoaXMgZmlsZSB3YXMgYXV0by1nZW5lcmF0ZWQuIERvIG5vdCBlZGl0IQojICAgICAgICAgIEFsbCB5b3VyIGVkaXQgbWlnaHQgYmUgb3ZlcndyaXR0ZW4hCkRFUExPWV9ESVI9e3suRGVwbG95RGlyfX0KCmNkICIke0RFUExPWV9ESVJ9IiB8fCBleGl0IDEKCnt7LSBkZWZpbmUgIlBETGlzdCJ9fQogIHt7LSByYW5nZSAkaWR4LCAkcGQgOj0gLn19CiAgICB7ey0gaWYgZXEgJGlkeCAwfX0KICAgICAge3stICRwZC5JUH19Ont7JHBkLkNsaWVudFBvcnR9fQogICAge3stIGVsc2UgLX19CiAgICAgICx7eyRwZC5JUH19Ont7JHBkLkNsaWVudFBvcnR9fQogICAge3stIGVuZH19CiAge3stIGVuZH19Cnt7LSBlbmR9fQoKe3stIGlmIC5OdW1hTm9kZX19CmV4ZWMgbnVtYWN0bCAtLWNwdW5vZGViaW5kPXt7Lk51bWFOb2RlfX0gLS1tZW1iaW5kPXt7Lk51bWFOb2RlfX0gZW52IEdPREVCVUc9bWFkdmRvbnRuZWVkPTEgYmluL3RpZGItc2VydmVyIFwKe3stIGVsc2V9fQpleGVjIGVudiBHT0RFQlVHPW1hZHZkb250bmVlZD0xIGJpbi90aWRiLXNlcnZlciBcCnt7LSBlbmR9fQogICAgLVAge3suUG9ydH19IFwKICAgIC0tc3RhdHVzPSJ7ey5TdGF0dXNQb3J0fX0iIFwKICAgIC0taG9zdD0ie3suTGlzdGVuSG9zdH19IiBcCiAgICAtLWFkdmVydGlzZS1hZGRyZXNzPSJ7ey5JUH19IiBcCiAgICAtLXN0b3JlPSJ0aWt2IiBcCiAgICAtLWNvbmZpZz0iY29uZi90aWRiLnRvbWwiIFwKICAgIC0tcGF0aD0ie3t0ZW1wbGF0ZSAiUERMaXN0IiAuRW5kcG9pbnRzfX0iIFwKICAgIC0tbG9nLXNsb3ctcXVlcnk9ImxvZy90aWRiX3Nsb3dfcXVlcnkubG9nIiBcCiAgICAtLWNvbmZpZz1jb25mL3RpZGIudG9tbCBcCiAgICAtLWxvZy1maWxlPSJ7ey5Mb2dEaXJ9fS90aWRiLmxvZyIgMj4+ICJ7ey5Mb2dEaXJ9fS90aWRiX3N0ZGVyci5sb2ciCg==" autogenFiles["/templates/scripts/run_tiflash.sh.tpl"] = "IyEvYmluL2Jhc2gKc2V0IC1lCgojIFdBUk5JTkc6IFRoaXMgZmlsZSB3YXMgYXV0by1nZW5lcmF0ZWQuIERvIG5vdCBlZGl0IQojICAgICAgICAgIEFsbCB5b3VyIGVkaXQgbWlnaHQgYmUgb3ZlcndyaXR0ZW4hCmNkICJ7ey5EZXBsb3lEaXJ9fSIgfHwgZXhpdCAxCgpleHBvcnQgUlVTVF9CQUNLVFJBQ0U9MQoKZXhwb3J0IFRaPSR7VFo6LS9ldGMvbG9jYWx0aW1lfQpleHBvcnQgTERfTElCUkFSWV9QQVRIPXt7LkRlcGxveURpcn19L2Jpbi90aWZsYXNoOiRMRF9MSUJSQVJZX1BBVEgKCmVjaG8gLW4gJ3N5bmMgLi4uICcKc3RhdD0kKHRpbWUgc3luYykKZWNobyBvawplY2hvICRzdGF0Cgp7ey0gaWYgLk51bWFOb2RlfX0KZXhlYyBudW1hY3RsIC0tY3B1bm9kZWJpbmQ9e3suTnVtYU5vZGV9fSAtLW1lbWJpbmQ9e3suTnVtYU5vZGV9fSAgXAp7ey0gZWxzZX19CmV4ZWMgXAp7ey0gZW5kfX0KICAgIGJpbi90aWZsYXNoL3RpZmxhc2ggc2VydmVyIC0tY29uZmlnLWZpbGUgY29uZi90aWZsYXNoLnRvbWw=" autogenFiles["/templates/scripts/run_tikv.sh.tpl"] = "IyEvYmluL2Jhc2gKc2V0IC1lCgojIFdBUk5JTkc6IFRoaXMgZmlsZSB3YXMgYXV0by1nZW5lcmF0ZWQuIERvIG5vdCBlZGl0IQojICAgICAgICAgIEFsbCB5b3VyIGVkaXQgbWlnaHQgYmUgb3ZlcndyaXR0ZW4hCmNkICJ7ey5EZXBsb3lEaXJ9fSIgfHwgZXhpdCAxCgplY2hvIC1uICdzeW5jIC4uLiAnCnN0YXQ9JCh0aW1lIHN5bmMgfHwgc3luYykKZWNobyBvawplY2hvICRzdGF0Cgp7ey0gZGVmaW5lICJQRExpc3QifX0KICB7ey0gcmFuZ2UgJGlkeCwgJHBkIDo9IC59fQogICAge3stIGlmIGVxICRpZHggMH19CiAgICAgIHt7LSAkcGQuSVB9fTp7eyRwZC5DbGllbnRQb3J0fX0KICAgIHt7LSBlbHNlIC19fQogICAgICAse3skcGQuSVB9fTp7eyRwZC5DbGllbnRQb3J0fX0KICAgIHt7LSBlbmR9fQogIHt7LSBlbmR9fQp7ey0gZW5kfX0KCnt7LSBpZiAuTnVtYU5vZGV9fQpleGVjIG51bWFjdGwgLS1jcHVub2RlYmluZD17ey5OdW1hTm9kZX19IC0tbWVtYmluZD17ey5OdW1hTm9kZX19IGJpbi90aWt2LXNlcnZlciBcCnt7LSBlbHNlfX0KZXhlYyBiaW4vdGlrdi1zZXJ2ZXIgXAp7ey0gZW5kfX0KICAgIC0tYWRkciAie3suTGlzdGVuSG9zdH19Ont7LlBvcnR9fSIgXAogICAgLS1hZHZlcnRpc2UtYWRkciAie3suSVB9fTp7ey5Qb3J0fX0iIFwKICAgIC0tc3RhdHVzLWFkZHIgInt7LklQfX06e3suU3RhdHVzUG9ydH19IiBcCiAgICAtLXBkICJ7e3RlbXBsYXRlICJQRExpc3QiIC5FbmRwb2ludHN9fSIgXAogICAgLS1kYXRhLWRpciAie3suRGF0YURpcn19IiBcCiAgICAtLWNvbmZpZyBjb25mL3Rpa3YudG9tbCBcCiAgICAtLWxvZy1maWxlICJ7ey5Mb2dEaXJ9fS90aWt2LmxvZyIgMj4+ICJ7ey5Mb2dEaXJ9fS90aWt2X3N0ZGVyci5sb2ciCg==" + autogenFiles["/templates/scripts/spark-env.sh.tpl"] = "IyEvdXNyL2Jpbi9lbnYgYmFzaAoKIwojIExpY2Vuc2VkIHRvIHRoZSBBcGFjaGUgU29mdHdhcmUgRm91bmRhdGlvbiAoQVNGKSB1bmRlciBvbmUgb3IgbW9yZQojIGNvbnRyaWJ1dG9yIGxpY2Vuc2UgYWdyZWVtZW50cy4gIFNlZSB0aGUgTk9USUNFIGZpbGUgZGlzdHJpYnV0ZWQgd2l0aAojIHRoaXMgd29yayBmb3IgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiByZWdhcmRpbmcgY29weXJpZ2h0IG93bmVyc2hpcC4KIyBUaGUgQVNGIGxpY2Vuc2VzIHRoaXMgZmlsZSB0byBZb3UgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMAojICh0aGUgIkxpY2Vuc2UiKTsgeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoCiMgdGhlIExpY2Vuc2UuICBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXQKIwojICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAojCiMgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQojIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuICJBUyBJUyIgQkFTSVMsCiMgV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuCiMgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAojIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLgojCgojIFRoaXMgZmlsZSBpcyBzb3VyY2VkIHdoZW4gcnVubmluZyB2YXJpb3VzIFNwYXJrIHByb2dyYW1zLgojIENvcHkgaXQgYXMgc3BhcmstZW52LnNoIGFuZCBlZGl0IHRoYXQgdG8gY29uZmlndXJlIFNwYXJrIGZvciB5b3VyIHNpdGUuCgojIE9wdGlvbnMgcmVhZCB3aGVuIGxhdW5jaGluZyBwcm9ncmFtcyBsb2NhbGx5IHdpdGgKIyAuL2Jpbi9ydW4tZXhhbXBsZSBvciAuL2Jpbi9zcGFyay1zdWJtaXQKIyAtIEhBRE9PUF9DT05GX0RJUiwgdG8gcG9pbnQgU3BhcmsgdG93YXJkcyBIYWRvb3AgY29uZmlndXJhdGlvbiBmaWxlcwojIC0gU1BBUktfTE9DQUxfSVAsIHRvIHNldCB0aGUgSVAgYWRkcmVzcyBTcGFyayBiaW5kcyB0byBvbiB0aGlzIG5vZGUKIyAtIFNQQVJLX1BVQkxJQ19ETlMsIHRvIHNldCB0aGUgcHVibGljIGRucyBuYW1lIG9mIHRoZSBkcml2ZXIgcHJvZ3JhbQojIC0gU1BBUktfQ0xBU1NQQVRILCBkZWZhdWx0IGNsYXNzcGF0aCBlbnRyaWVzIHRvIGFwcGVuZAoKIyBPcHRpb25zIHJlYWQgYnkgZXhlY3V0b3JzIGFuZCBkcml2ZXJzIHJ1bm5pbmcgaW5zaWRlIHRoZSBjbHVzdGVyCiMgLSBTUEFSS19MT0NBTF9JUCwgdG8gc2V0IHRoZSBJUCBhZGRyZXNzIFNwYXJrIGJpbmRzIHRvIG9uIHRoaXMgbm9kZQojIC0gU1BBUktfUFVCTElDX0ROUywgdG8gc2V0IHRoZSBwdWJsaWMgRE5TIG5hbWUgb2YgdGhlIGRyaXZlciBwcm9ncmFtCiMgLSBTUEFSS19DTEFTU1BBVEgsIGRlZmF1bHQgY2xhc3NwYXRoIGVudHJpZXMgdG8gYXBwZW5kCiMgLSBTUEFSS19MT0NBTF9ESVJTLCBzdG9yYWdlIGRpcmVjdG9yaWVzIHRvIHVzZSBvbiB0aGlzIG5vZGUgZm9yIHNodWZmbGUgYW5kIFJERCBkYXRhCiMgLSBNRVNPU19OQVRJVkVfSkFWQV9MSUJSQVJZLCB0byBwb2ludCB0byB5b3VyIGxpYm1lc29zLnNvIGlmIHlvdSB1c2UgTWVzb3MKCiMgT3B0aW9ucyByZWFkIGluIFlBUk4gY2xpZW50IG1vZGUKIyAtIEhBRE9PUF9DT05GX0RJUiwgdG8gcG9pbnQgU3BhcmsgdG93YXJkcyBIYWRvb3AgY29uZmlndXJhdGlvbiBmaWxlcwojIC0gU1BBUktfRVhFQ1VUT1JfSU5TVEFOQ0VTLCBOdW1iZXIgb2YgZXhlY3V0b3JzIHRvIHN0YXJ0IChEZWZhdWx0OiAyKQojIC0gU1BBUktfRVhFQ1VUT1JfQ09SRVMsIE51bWJlciBvZiBjb3JlcyBmb3IgdGhlIGV4ZWN1dG9ycyAoRGVmYXVsdDogMSkuCiMgLSBTUEFSS19FWEVDVVRPUl9NRU1PUlksIE1lbW9yeSBwZXIgRXhlY3V0b3IgKGUuZy4gMTAwME0sIDJHKSAoRGVmYXVsdDogMUcpCiMgLSBTUEFSS19EUklWRVJfTUVNT1JZLCBNZW1vcnkgZm9yIERyaXZlciAoZS5nLiAxMDAwTSwgMkcpIChEZWZhdWx0OiAxRykKCiMgT3B0aW9ucyBmb3IgdGhlIGRhZW1vbnMgdXNlZCBpbiB0aGUgc3RhbmRhbG9uZSBkZXBsb3kgbW9kZQojIC0gU1BBUktfTUFTVEVSX0hPU1QsIHRvIGJpbmQgdGhlIG1hc3RlciB0byBhIGRpZmZlcmVudCBJUCBhZGRyZXNzIG9yIGhvc3RuYW1lCiMgLSBTUEFSS19NQVNURVJfUE9SVCAvIFNQQVJLX01BU1RFUl9XRUJVSV9QT1JULCB0byB1c2Ugbm9uLWRlZmF1bHQgcG9ydHMgZm9yIHRoZSBtYXN0ZXIKIyAtIFNQQVJLX01BU1RFUl9PUFRTLCB0byBzZXQgY29uZmlnIHByb3BlcnRpZXMgb25seSBmb3IgdGhlIG1hc3RlciAoZS5nLiAiLUR4PXkiKQojIC0gU1BBUktfV09SS0VSX0NPUkVTLCB0byBzZXQgdGhlIG51bWJlciBvZiBjb3JlcyB0byB1c2Ugb24gdGhpcyBtYWNoaW5lCiMgLSBTUEFSS19XT1JLRVJfTUVNT1JZLCB0byBzZXQgaG93IG11Y2ggdG90YWwgbWVtb3J5IHdvcmtlcnMgaGF2ZSB0byBnaXZlIGV4ZWN1dG9ycyAoZS5nLiAxMDAwbSwgMmcpCiMgLSBTUEFSS19XT1JLRVJfUE9SVCAvIFNQQVJLX1dPUktFUl9XRUJVSV9QT1JULCB0byB1c2Ugbm9uLWRlZmF1bHQgcG9ydHMgZm9yIHRoZSB3b3JrZXIKIyAtIFNQQVJLX1dPUktFUl9JTlNUQU5DRVMsIHRvIHNldCB0aGUgbnVtYmVyIG9mIHdvcmtlciBwcm9jZXNzZXMgcGVyIG5vZGUKIyAtIFNQQVJLX1dPUktFUl9ESVIsIHRvIHNldCB0aGUgd29ya2luZyBkaXJlY3Rvcnkgb2Ygd29ya2VyIHByb2Nlc3NlcwojIC0gU1BBUktfV09SS0VSX09QVFMsIHRvIHNldCBjb25maWcgcHJvcGVydGllcyBvbmx5IGZvciB0aGUgd29ya2VyIChlLmcuICItRHg9eSIpCiMgLSBTUEFSS19EQUVNT05fTUVNT1JZLCB0byBhbGxvY2F0ZSB0byB0aGUgbWFzdGVyLCB3b3JrZXIgYW5kIGhpc3Rvcnkgc2VydmVyIHRoZW1zZWx2ZXMgKGRlZmF1bHQ6IDFnKS4KIyAtIFNQQVJLX0hJU1RPUllfT1BUUywgdG8gc2V0IGNvbmZpZyBwcm9wZXJ0aWVzIG9ubHkgZm9yIHRoZSBoaXN0b3J5IHNlcnZlciAoZS5nLiAiLUR4PXkiKQojIC0gU1BBUktfU0hVRkZMRV9PUFRTLCB0byBzZXQgY29uZmlnIHByb3BlcnRpZXMgb25seSBmb3IgdGhlIGV4dGVybmFsIHNodWZmbGUgc2VydmljZSAoZS5nLiAiLUR4PXkiKQojIC0gU1BBUktfREFFTU9OX0pBVkFfT1BUUywgdG8gc2V0IGNvbmZpZyBwcm9wZXJ0aWVzIGZvciBhbGwgZGFlbW9ucyAoZS5nLiAiLUR4PXkiKQojIC0gU1BBUktfUFVCTElDX0ROUywgdG8gc2V0IHRoZSBwdWJsaWMgZG5zIG5hbWUgb2YgdGhlIG1hc3RlciBvciB3b3JrZXJzCgojIEdlbmVyaWMgb3B0aW9ucyBmb3IgdGhlIGRhZW1vbnMgdXNlZCBpbiB0aGUgc3RhbmRhbG9uZSBkZXBsb3kgbW9kZQojIC0gU1BBUktfQ09ORl9ESVIgICAgICBBbHRlcm5hdGUgY29uZiBkaXIuIChEZWZhdWx0OiAke1NQQVJLX0hPTUV9L2NvbmYpCiMgLSBTUEFSS19MT0dfRElSICAgICAgIFdoZXJlIGxvZyBmaWxlcyBhcmUgc3RvcmVkLiAgKERlZmF1bHQ6ICR7U1BBUktfSE9NRX0vbG9ncykKIyAtIFNQQVJLX1BJRF9ESVIgICAgICAgV2hlcmUgdGhlIHBpZCBmaWxlIGlzIHN0b3JlZC4gKERlZmF1bHQ6IC90bXApCiMgLSBTUEFSS19JREVOVF9TVFJJTkcgIEEgc3RyaW5nIHJlcHJlc2VudGluZyB0aGlzIGluc3RhbmNlIG9mIHNwYXJrLiAoRGVmYXVsdDogJFVTRVIpCiMgLSBTUEFSS19OSUNFTkVTUyAgICAgIFRoZSBzY2hlZHVsaW5nIHByaW9yaXR5IGZvciBkYWVtb25zLiAoRGVmYXVsdDogMCkKIyAtIFNQQVJLX05PX0RBRU1PTklaRSAgUnVuIHRoZSBwcm9wb3NlZCBjb21tYW5kIGluIHRoZSBmb3JlZ3JvdW5kLiBJdCB3aWxsIG5vdCBvdXRwdXQgYSBQSUQgZmlsZS4KCiNleHBvcnQgSkFWQV9IT01FLCB0byBzZXQgamRrIGhvbWUKCnt7IHJhbmdlICRrLCAkdiA6PSAuQ3VzdG9tRW52c319Cnt7ICRrIH19PXt7ICR2IH19Cnt7LSBlbmQgfX0KCnt7LSBpZiAuVGlTcGFya01hc3Rlcn19ClNQQVJLX01BU1RFUl9IT1NUPXt7LlRpU3BhcmtNYXN0ZXJ9fQp7ey0gZW5kfX0Ke3stIGlmIG5lIC5NYXN0ZXJQb3J0IDB9fQpTUEFSS19NQVNURVJfUE9SVD17ey5NYXN0ZXJQb3J0fX0Ke3stIGVuZH19Cnt7LSBpZiBuZSAuTWFzdGVyVUlQb3J0IDB9fQpTUEFSS19NQVNURVJfV0VCVUlfUE9SVD17ey5NYXN0ZXJVSVBvcnR9fQp7ey0gZW5kfX0Ke3stIGlmIG5lIC5Xb3JrZXJQb3J0IDB9fQpTUEFSS19XT1JLRVJfUE9SVD17ey5Xb3JrZXJQb3J0fX0Ke3stIGVuZH19Cnt7LSBpZiBuZSAuV29ya2VyVUlQb3J0IDB9fQpTUEFSS19XT1JLRVJfV0VCVUlfUE9SVD17ey5Xb3JrZXJVSVBvcnR9fQp7ey0gZW5kfX0K" + autogenFiles["/templates/scripts/start_tispark_slave.sh.tpl"] = "IyEvdXNyL2Jpbi9lbnYgYmFzaAoKIwojIExpY2Vuc2VkIHRvIHRoZSBBcGFjaGUgU29mdHdhcmUgRm91bmRhdGlvbiAoQVNGKSB1bmRlciBvbmUgb3IgbW9yZQojIGNvbnRyaWJ1dG9yIGxpY2Vuc2UgYWdyZWVtZW50cy4gIFNlZSB0aGUgTk9USUNFIGZpbGUgZGlzdHJpYnV0ZWQgd2l0aAojIHRoaXMgd29yayBmb3IgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiByZWdhcmRpbmcgY29weXJpZ2h0IG93bmVyc2hpcC4KIyBUaGUgQVNGIGxpY2Vuc2VzIHRoaXMgZmlsZSB0byBZb3UgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMAojICh0aGUgIkxpY2Vuc2UiKTsgeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoCiMgdGhlIExpY2Vuc2UuICBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXQKIwojICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAojCiMgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQojIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuICJBUyBJUyIgQkFTSVMsCiMgV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuCiMgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAojIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLgojCgojIFN0YXJ0cyBhIHNsYXZlIG9uIHRoZSBtYWNoaW5lIHRoaXMgc2NyaXB0IGlzIGV4ZWN1dGVkIG9uLgojCiMgRW52aXJvbm1lbnQgVmFyaWFibGVzCiMKIyAgIFNQQVJLX1dPUktFUl9JTlNUQU5DRVMgIFRoZSBudW1iZXIgb2Ygd29ya2VyIGluc3RhbmNlcyB0byBydW4gb24gdGhpcwojICAgICAgICAgICAgICAgICAgICAgICAgICAgc2xhdmUuICBEZWZhdWx0IGlzIDEuCiMgICBTUEFSS19XT1JLRVJfUE9SVCAgICAgICBUaGUgYmFzZSBwb3J0IG51bWJlciBmb3IgdGhlIGZpcnN0IHdvcmtlci4gSWYgc2V0LAojICAgICAgICAgICAgICAgICAgICAgICAgICAgc3Vic2VxdWVudCB3b3JrZXJzIHdpbGwgaW5jcmVtZW50IHRoaXMgbnVtYmVyLiAgSWYKIyAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuc2V0LCBTcGFyayB3aWxsIGZpbmQgYSB2YWxpZCBwb3J0IG51bWJlciwgYnV0CiMgICAgICAgICAgICAgICAgICAgICAgICAgICB3aXRoIG5vIGd1YXJhbnRlZSBvZiBhIHByZWRpY3RhYmxlIHBhdHRlcm4uCiMgICBTUEFSS19XT1JLRVJfV0VCVUlfUE9SVCBUaGUgYmFzZSBwb3J0IGZvciB0aGUgd2ViIGludGVyZmFjZSBvZiB0aGUgZmlyc3QKIyAgICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmtlci4gIFN1YnNlcXVlbnQgd29ya2VycyB3aWxsIGluY3JlbWVudCB0aGlzCiMgICAgICAgICAgICAgICAgICAgICAgICAgICBudW1iZXIuICBEZWZhdWx0IGlzIDgwODEuCgppZiBbIC16ICIke1NQQVJLX0hPTUV9IiBdOyB0aGVuCiAgZXhwb3J0IFNQQVJLX0hPTUU9IiQoY2QgImBkaXJuYW1lICIkMCJgIi8uLjsgcHdkKSIKZmkKCiMgTk9URTogVGhpcyBleGFjdCBjbGFzcyBuYW1lIGlzIG1hdGNoZWQgZG93bnN0cmVhbSBieSBTcGFya1N1Ym1pdC4KIyBBbnkgY2hhbmdlcyBuZWVkIHRvIGJlIHJlZmxlY3RlZCB0aGVyZS4KQ0xBU1M9Im9yZy5hcGFjaGUuc3BhcmsuZGVwbG95Lndvcmtlci5Xb3JrZXIiCgppZiBbWyAiJEAiID0gKi0taGVscCBdXSB8fCBbWyAiJEAiID0gKi1oIF1dOyB0aGVuCiAgZWNobyAiVXNhZ2U6IC4vc2Jpbi9zdGFydC1zbGF2ZS5zaCBbb3B0aW9uc10gPG1hc3Rlcj4iCiAgcGF0dGVybj0iVXNhZ2U6IgogIHBhdHRlcm4rPSJcfFVzaW5nIFNwYXJrJ3MgZGVmYXVsdCBsb2c0aiBwcm9maWxlOiIKICBwYXR0ZXJuKz0iXHxSZWdpc3RlcmVkIHNpZ25hbCBoYW5kbGVycyBmb3IiCgogICIke1NQQVJLX0hPTUV9Ii9iaW4vc3BhcmstY2xhc3MgJENMQVNTIC0taGVscCAyPiYxIHwgZ3JlcCAtdiAiJHBhdHRlcm4iIDE+JjIKICBleGl0IDEKZmkKCi4gIiR7U1BBUktfSE9NRX0vc2Jpbi9zcGFyay1jb25maWcuc2giCgouICIke1NQQVJLX0hPTUV9L2Jpbi9sb2FkLXNwYXJrLWVudi5zaCIKCiMgRmlyc3QgYXJndW1lbnQgc2hvdWxkIGJlIHRoZSBtYXN0ZXI7IHdlIG5lZWQgdG8gc3RvcmUgaXQgYXNpZGUgYmVjYXVzZSB3ZSBtYXkKIyBuZWVkIHRvIGluc2VydCBhcmd1bWVudHMgYmV0d2VlbiBpdCBhbmQgdGhlIG90aGVyIGFyZ3VtZW50cwoKe3stIGlmIC5UaVNwYXJrTWFzdGVyfX0KTUFTVEVSPXNwYXJrOi8ve3suVGlTcGFya01hc3Rlcn19Ont7Lk1hc3RlclBvcnR9fQpzaGlmdAp7ey0gZW5kfX0KCiMgRGV0ZXJtaW5lIGRlc2lyZWQgd29ya2VyIHBvcnQKaWYgWyAiJFNQQVJLX1dPUktFUl9XRUJVSV9QT1JUIiA9ICIiIF07IHRoZW4KICBTUEFSS19XT1JLRVJfV0VCVUlfUE9SVD04MDgxCmZpCgojIFN0YXJ0IHVwIHRoZSBhcHByb3ByaWF0ZSBudW1iZXIgb2Ygd29ya2VycyBvbiB0aGlzIG1hY2hpbmUuCiMgcXVpY2sgbG9jYWwgZnVuY3Rpb24gdG8gc3RhcnQgYSB3b3JrZXIKZnVuY3Rpb24gc3RhcnRfaW5zdGFuY2UgewogIFdPUktFUl9OVU09JDEKICBzaGlmdAoKICBpZiBbICIkU1BBUktfV09SS0VSX1BPUlQiID0gIiIgXTsgdGhlbgogICAgUE9SVF9GTEFHPQogICAgUE9SVF9OVU09CiAgZWxzZQogICAgUE9SVF9GTEFHPSItLXBvcnQiCiAgICBQT1JUX05VTT0kKCggJFNQQVJLX1dPUktFUl9QT1JUICsgJFdPUktFUl9OVU0gLSAxICkpCiAgZmkKICBXRUJVSV9QT1JUPSQoKCAkU1BBUktfV09SS0VSX1dFQlVJX1BPUlQgKyAkV09SS0VSX05VTSAtIDEgKSkKCiAgIiR7U1BBUktfSE9NRX0vc2JpbiIvc3BhcmstZGFlbW9uLnNoIHN0YXJ0ICRDTEFTUyAkV09SS0VSX05VTSBcCiAgICAgLS13ZWJ1aS1wb3J0ICIkV0VCVUlfUE9SVCIgJFBPUlRfRkxBRyAkUE9SVF9OVU0gJE1BU1RFUiAiJEAiCn0KCmlmIFsgIiRTUEFSS19XT1JLRVJfSU5TVEFOQ0VTIiA9ICIiIF07IHRoZW4KICBzdGFydF9pbnN0YW5jZSAxICIkQCIKZWxzZQogIGZvciAoKGk9MDsgaTwkU1BBUktfV09SS0VSX0lOU1RBTkNFUzsgaSsrKSk7IGRvCiAgICBzdGFydF9pbnN0YW5jZSAkKCggMSArICRpICkpICIkQCIKICBkb25lCmZpCg==" autogenFiles["/templates/systemd/system.service.tpl"] = "W1VuaXRdCkRlc2NyaXB0aW9uPXt7LlNlcnZpY2VOYW1lfX0gc2VydmljZQpBZnRlcj1zeXNsb2cudGFyZ2V0IG5ldHdvcmsudGFyZ2V0IHJlbW90ZS1mcy50YXJnZXQgbnNzLWxvb2t1cC50YXJnZXQKCltTZXJ2aWNlXQp7ey0gaWYgLk1lbW9yeUxpbWl0fX0KTWVtb3J5TGltaXQ9e3suTWVtb3J5TGltaXR9fQp7ey0gZW5kfX0Ke3stIGlmIC5DUFVRdW90YX19CkNQVVF1b3RhPXt7LkNQVVF1b3RhfX0Ke3stIGVuZH19Cnt7LSBpZiAuSU9SZWFkQmFuZHdpZHRoTWF4fX0KSU9SZWFkQmFuZHdpZHRoTWF4PXt7LklPUmVhZEJhbmR3aWR0aE1heH19Cnt7LSBlbmR9fQp7ey0gaWYgLklPV3JpdGVCYW5kd2lkdGhNYXh9fQpJT1dyaXRlQmFuZHdpZHRoTWF4PXt7LklPV3JpdGVCYW5kd2lkdGhNYXh9fQp7ey0gZW5kfX0KTGltaXROT0ZJTEU9MTAwMDAwMAojTGltaXRDT1JFPWluZmluaXR5CkxpbWl0U1RBQ0s9MTA0ODU3NjAKClVzZXI9e3suVXNlcn19CkV4ZWNTdGFydD17ey5EZXBsb3lEaXJ9fS9zY3JpcHRzL3J1bl97ey5TZXJ2aWNlTmFtZX19LnNoCgp7ey0gaWYgLlJlc3RhcnR9fQpSZXN0YXJ0PXt7LlJlc3RhcnR9fQp7e2Vsc2V9fQpSZXN0YXJ0PWFsd2F5cwp7e2VuZH19ClJlc3RhcnRTZWM9MTVzCnt7LSBpZiAuRGlzYWJsZVNlbmRTaWdraWxsfX0KU2VuZFNJR0tJTEw9bm8Ke3stIGVuZH19CgpbSW5zdGFsbF0KV2FudGVkQnk9bXVsdGktdXNlci50YXJnZXQK" + autogenFiles["/templates/systemd/tispark.service.tpl"] = "W1VuaXRdCkRlc2NyaXB0aW9uPXt7LlNlcnZpY2VOYW1lfX0gc2VydmljZQpBZnRlcj1zeXNsb2cudGFyZ2V0IG5ldHdvcmsudGFyZ2V0IHJlbW90ZS1mcy50YXJnZXQgbnNzLWxvb2t1cC50YXJnZXQKCltTZXJ2aWNlXQpVc2VyPXt7LlVzZXJ9fQpFeGVjU3RhcnQ9e3suRGVwbG95RGlyfX0vc2Jpbi9zdGFydC17ey5TZXJ2aWNlTmFtZX19LnNoCkV4ZWNTdG9wPXt7LkRlcGxveURpcn19L3NiaW4vc3RvcC17ey5TZXJ2aWNlTmFtZX19LnNoClR5cGU9Zm9ya2luZwp7ey0gaWYgLlJlc3RhcnR9fQpSZXN0YXJ0PXt7LlJlc3RhcnR9fQp7e2Vsc2V9fQpSZXN0YXJ0PWFsd2F5cwp7e2VuZH19ClJlc3RhcnRTZWM9MTVzClNlbmRTSUdLSUxMPW5vCgpbSW5zdGFsbF0KV2FudGVkQnk9bXVsdGktdXNlci50YXJnZXQK" } diff --git a/pkg/cluster/embed/embed_test.go b/pkg/cluster/embed/embed_test.go index 69f450109b..e7ec368901 100644 --- a/pkg/cluster/embed/embed_test.go +++ b/pkg/cluster/embed/embed_test.go @@ -38,7 +38,7 @@ func getAllFilePaths(dir string) (paths []string, err error) { } // Test can read all file in /templates -// If files in /templates changed, you may need run `make pkager` to regenerate the pkager.go +// If files in /templates changed, you may need run `make pkger` to regenerate the autogen_pkger.go func (s *embedSuite) TestCanReadTemplates(c *check.C) { root, err := filepath.Abs("../../../") c.Assert(err, check.IsNil) diff --git a/pkg/cluster/executor/ssh.go b/pkg/cluster/executor/ssh.go index 20e51f5b6c..21577f60fd 100644 --- a/pkg/cluster/executor/ssh.go +++ b/pkg/cluster/executor/ssh.go @@ -21,12 +21,11 @@ import ( "strings" "time" - utils2 "github.com/pingcap/tiup/pkg/utils" - "github.com/appleboy/easyssh-proxy" "github.com/fatih/color" "github.com/joomcode/errorx" "github.com/pingcap/tiup/pkg/cliutil" + "github.com/pingcap/tiup/pkg/utils" "go.uber.org/zap" ) @@ -196,7 +195,7 @@ func (e *SSHExecutor) Transfer(src string, dst string, download bool) error { defer session.Close() targetPath := filepath.Dir(dst) - if err = utils2.CreateDir(targetPath); err != nil { + if err = utils.CreateDir(targetPath); err != nil { return err } targetFile, err := os.Create(dst) diff --git a/pkg/cluster/operation/destroy.go b/pkg/cluster/operation/destroy.go index 4ac04aec3d..dccc179516 100644 --- a/pkg/cluster/operation/destroy.go +++ b/pkg/cluster/operation/destroy.go @@ -271,7 +271,9 @@ func DestroyComponent(getter ExecutorGetter, instances []spec.Instance, cls topo delPaths.Insert(deployDir) } - delPaths.Insert(fmt.Sprintf("/etc/systemd/system/%s", ins.ServiceName())) + if svc := ins.ServiceName(); svc != "" { + delPaths.Insert(fmt.Sprintf("/etc/systemd/system/%s", svc)) + } log.Debugf("Deleting paths on %s: %s", ins.GetHost(), strings.Join(delPaths.Slice(), " ")) c := module.ShellModuleConfig{ Command: fmt.Sprintf("rm -rf %s;", strings.Join(delPaths.Slice(), " ")), diff --git a/pkg/cluster/spec/bindversion.go b/pkg/cluster/spec/bindversion.go index 99394df077..6565e4b36e 100644 --- a/pkg/cluster/spec/bindversion.go +++ b/pkg/cluster/spec/bindversion.go @@ -13,6 +13,11 @@ package spec +import ( + "fmt" + "strings" +) + // ComponentVersion maps the TiDB version to the third components binding version func ComponentVersion(comp, version string) string { switch comp { @@ -26,7 +31,20 @@ func ComponentVersion(comp, version string) string { return "v0.7.0" case ComponentCheckCollector: return "v0.3.1" + case ComponentTiSpark: + return "v2.3.1" + case ComponentSpark: + return "v2.4.3" default: return version } } + +// ComponentSubDir maps a component with version to a subdir if needed +func ComponentSubDir(comp, version string) string { + switch comp { + case ComponentSpark: + return fmt.Sprintf("spark-%s-bin-hadoop2.7", strings.TrimLeft(version, "v")) + } + return "" +} diff --git a/pkg/cluster/spec/instance.go b/pkg/cluster/spec/instance.go index 226e80bbf6..11969e429b 100644 --- a/pkg/cluster/spec/instance.go +++ b/pkg/cluster/spec/instance.go @@ -40,6 +40,8 @@ const ( ComponentDrainer = "drainer" ComponentPump = "pump" ComponentCDC = "cdc" + ComponentTiSpark = "tispark" + ComponentSpark = "spark" ComponentAlertManager = "alertmanager" ComponentPrometheus = "prometheus" ComponentPushwaygate = "pushgateway" @@ -212,6 +214,13 @@ func (i *instance) InstanceName() string { // ServiceName implements Instance interface func (i *instance) ServiceName() string { + switch i.ComponentName() { + case ComponentSpark, ComponentTiSpark: + if i.port > 0 { + return fmt.Sprintf("%s-%d.service", i.Role(), i.port) + } + return fmt.Sprintf("%s.service", i.Role()) + } if i.port > 0 { return fmt.Sprintf("%s-%d.service", i.name, i.port) } @@ -272,11 +281,19 @@ func (i *instance) LogDir() string { } func (i *instance) OS() string { - return reflect.ValueOf(i.InstanceSpec).FieldByName("OS").Interface().(string) + v := reflect.ValueOf(i.InstanceSpec).FieldByName("OS") + if !v.IsValid() { + return "" + } + return v.Interface().(string) } func (i *instance) Arch() string { - return reflect.ValueOf(i.InstanceSpec).FieldByName("Arch").Interface().(string) + v := reflect.ValueOf(i.InstanceSpec).FieldByName("Arch") + if !v.IsValid() { + return "" + } + return v.Interface().(string) } // PrepareStart checks instance requirements before starting @@ -302,9 +319,10 @@ func MergeResourceControl(lhs, rhs meta.ResourceControl) meta.ResourceControl { } func (i *instance) resourceControl() meta.ResourceControl { - return reflect.ValueOf(i.InstanceSpec). - FieldByName("ResourceControl"). - Interface().(meta.ResourceControl) + if v := reflect.ValueOf(i.InstanceSpec).FieldByName("ResourceControl"); v.IsValid() { + return v.Interface().(meta.ResourceControl) + } + return meta.ResourceControl{} } func (i *instance) GetPort() int { diff --git a/pkg/cluster/spec/spec.go b/pkg/cluster/spec/spec.go index af9fb4d824..a94cdcd202 100644 --- a/pkg/cluster/spec/spec.go +++ b/pkg/cluster/spec/spec.go @@ -36,7 +36,11 @@ const ( // general role names var ( - RoleMonitor = "monitor" + RoleMonitor = "monitor" + RoleTiSparkMaster = "tispark-master" + RoleTiSparkWorker = "tispark-worker" + ErrNoTiSparkMaster = errors.New("there must be a Spark master node if you want to use the TiSpark component") + ErrMultipleTiSparkMaster = errors.New("a TiSpark enabled cluster with more than 1 Spark master node is not supported") ) type ( @@ -86,19 +90,21 @@ type ( // Specification represents the specification of topology.yaml Specification struct { - GlobalOptions GlobalOptions `yaml:"global,omitempty"` - MonitoredOptions MonitoredOptions `yaml:"monitored,omitempty"` - ServerConfigs ServerConfigs `yaml:"server_configs,omitempty"` - TiDBServers []TiDBSpec `yaml:"tidb_servers"` - TiKVServers []TiKVSpec `yaml:"tikv_servers"` - TiFlashServers []TiFlashSpec `yaml:"tiflash_servers"` - PDServers []PDSpec `yaml:"pd_servers"` - PumpServers []PumpSpec `yaml:"pump_servers,omitempty"` - Drainers []DrainerSpec `yaml:"drainer_servers,omitempty"` - CDCServers []CDCSpec `yaml:"cdc_servers,omitempty"` - Monitors []PrometheusSpec `yaml:"monitoring_servers"` - Grafana []GrafanaSpec `yaml:"grafana_servers,omitempty"` - Alertmanager []AlertManagerSpec `yaml:"alertmanager_servers,omitempty"` + GlobalOptions GlobalOptions `yaml:"global,omitempty"` + MonitoredOptions MonitoredOptions `yaml:"monitored,omitempty"` + ServerConfigs ServerConfigs `yaml:"server_configs,omitempty"` + TiDBServers []TiDBSpec `yaml:"tidb_servers"` + TiKVServers []TiKVSpec `yaml:"tikv_servers"` + TiFlashServers []TiFlashSpec `yaml:"tiflash_servers"` + PDServers []PDSpec `yaml:"pd_servers"` + PumpServers []PumpSpec `yaml:"pump_servers,omitempty"` + Drainers []DrainerSpec `yaml:"drainer_servers,omitempty"` + CDCServers []CDCSpec `yaml:"cdc_servers,omitempty"` + TiSparkMasters []TiSparkMasterSpec `yaml:"tispark_masters,omitempty"` + TiSparkWorkers []TiSparkWorkerSpec `yaml:"tispark_workers,omitempty"` + Monitors []PrometheusSpec `yaml:"monitoring_servers"` + Grafana []GrafanaSpec `yaml:"grafana_servers,omitempty"` + Alertmanager []AlertManagerSpec `yaml:"alertmanager_servers,omitempty"` } ) @@ -480,7 +486,7 @@ func (s *Specification) CountDir(targetHost, dirPrefix string) int { } } dir = clusterutil.Abs(s.GlobalOptions.User, dir) - dirStats[host+dir] += 1 + dirStats[host+dir]++ } } } @@ -495,6 +501,23 @@ func (s *Specification) CountDir(targetHost, dirPrefix string) int { return count } +func (s *Specification) validateTiSparkSpec() error { + // There must be a Spark master + if len(s.TiSparkMasters) == 0 { + if len(s.TiSparkWorkers) == 0 { + return nil + } + return ErrNoTiSparkMaster + } + + // We only support 1 Spark master at present + if len(s.TiSparkMasters) > 1 { + return ErrMultipleTiSparkMaster + } + + return nil +} + // Validate validates the topology specification and produce error if the // specification invalid (e.g: port conflicts or directory conflicts) func (s *Specification) Validate() error { @@ -506,7 +529,11 @@ func (s *Specification) Validate() error { return err } - return s.dirConflictsDetect() + if err := s.dirConflictsDetect(); err != nil { + return err + } + + return s.validateTiSparkSpec() } // GetPDList returns a list of PD API hosts of the current cluster @@ -540,6 +567,8 @@ func (s *Specification) Merge(that *Specification) *Specification { PumpServers: append(s.PumpServers, that.PumpServers...), Drainers: append(s.Drainers, that.Drainers...), CDCServers: append(s.CDCServers, that.CDCServers...), + TiSparkMasters: append(s.TiSparkMasters, that.TiSparkMasters...), + TiSparkWorkers: append(s.TiSparkWorkers, that.TiSparkWorkers...), Monitors: append(s.Monitors, that.Monitors...), Grafana: append(s.Grafana, that.Grafana...), Alertmanager: append(s.Alertmanager, that.Alertmanager...), @@ -735,6 +764,8 @@ func (s *Specification) ComponentsByStartOrder() (comps []Component) { comps = append(comps, &MonitorComponent{s}) comps = append(comps, &GrafanaComponent{s}) comps = append(comps, &AlertManagerComponent{s}) + comps = append(comps, &TiSparkMasterComponent{s}) + comps = append(comps, &TiSparkWorkerComponent{s}) return } diff --git a/pkg/cluster/spec/spec_test.go b/pkg/cluster/spec/spec_test.go index 6a4f131894..013cdd29d4 100644 --- a/pkg/cluster/spec/spec_test.go +++ b/pkg/cluster/spec/spec_test.go @@ -231,7 +231,6 @@ tikv_servers: `), &topo) c.Assert(err, NotNil) c.Assert(err.Error(), Equals, "port conflict for '1234' between 'tidb_servers:172.16.5.138.port' and 'monitored:172.16.5.138.node_exporter_port'") - } func (s *metaSuiteTopo) TestPlatformConflicts(c *C) { @@ -277,7 +276,6 @@ tikv_servers: `), &topo) c.Assert(err, NotNil) c.Assert(err.Error(), Equals, "platform mismatch for '172.16.5.138' between 'tidb_servers:darwin/arm64' and 'tikv_servers:linux/arm64'") - } func (s *metaSuiteTopo) TestCountDir(c *C) { @@ -727,3 +725,49 @@ item7 = 700 c.Assert(err, IsNil) c.Assert(string(merge2), DeepEquals, expected) } + +func (s *metaSuiteTopo) TestTiSparkSpecValidation(c *C) { + topo := Specification{} + err := yaml.Unmarshal([]byte(` +pd_servers: + - host: 172.16.5.138 + port: 1234 +tispark_masters: + - host: 172.16.5.138 + port: 1235 +tispark_workers: + - host: 172.16.5.138 + port: 1236 + - host: 172.16.5.139 + port: 1235 +`), &topo) + c.Assert(err, IsNil) + + topo = Specification{} + err = yaml.Unmarshal([]byte(` +pd_servers: + - host: 172.16.5.138 + port: 1234 +tispark_masters: + - host: 172.16.5.138 + port: 1235 + - host: 172.16.5.139 + port: 1235 +`), &topo) + c.Assert(err, NotNil) + c.Assert(err.Error(), Equals, "a TiSpark enabled cluster with more than 1 Spark master node is not supported") + + topo = Specification{} + err = yaml.Unmarshal([]byte(` +pd_servers: + - host: 172.16.5.138 + port: 1234 +tispark_workers: + - host: 172.16.5.138 + port: 1235 + - host: 172.16.5.139 + port: 1235 +`), &topo) + c.Assert(err, NotNil) + c.Assert(err.Error(), Equals, "there must be a Spark master node if you want to use the TiSpark component") +} diff --git a/pkg/cluster/spec/tispark.go b/pkg/cluster/spec/tispark.go new file mode 100644 index 0000000000..7cabca5ec9 --- /dev/null +++ b/pkg/cluster/spec/tispark.go @@ -0,0 +1,381 @@ +// 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 spec + +import ( + "fmt" + "io/ioutil" + "path/filepath" + "reflect" + "strings" + + "github.com/google/uuid" + "github.com/pingcap/errors" + "github.com/pingcap/tiup/pkg/cluster/executor" + "github.com/pingcap/tiup/pkg/cluster/template/config" + "github.com/pingcap/tiup/pkg/cluster/template/scripts" + system "github.com/pingcap/tiup/pkg/cluster/template/systemd" + "github.com/pingcap/tiup/pkg/meta" +) + +// TiSparkMasterSpec is the topology specification for TiSpark master node +type TiSparkMasterSpec struct { + Host string `yaml:"host"` + SSHPort int `yaml:"ssh_port,omitempty"` + Imported bool `yaml:"imported,omitempty"` + Port int `yaml:"port" default:"7077"` + WebPort int `yaml:"web_port" default:"8080"` + DeployDir string `yaml:"deploy_dir,omitempty"` + SparkConfigs map[string]interface{} `yaml:"spark_config,omitempty"` + SparkEnvs map[string]string `yaml:"spark_env,omitempty"` + Arch string `yaml:"arch,omitempty"` + OS string `yaml:"os,omitempty"` +} + +// Role returns the component role of the instance +func (s TiSparkMasterSpec) Role() string { + return RoleTiSparkMaster +} + +// SSH returns the host and SSH port of the instance +func (s TiSparkMasterSpec) SSH() (string, int) { + return s.Host, s.SSHPort +} + +// GetMainPort returns the main port of the instance +func (s TiSparkMasterSpec) GetMainPort() int { + return s.Port +} + +// IsImported returns if the node is imported from TiDB-Ansible +func (s TiSparkMasterSpec) IsImported() bool { + return s.Imported +} + +// Status queries current status of the instance +func (s TiSparkMasterSpec) Status(pdList ...string) string { + url := fmt.Sprintf("http://%s:%d/", s.Host, s.WebPort) + return statusByURL(url) +} + +// TiSparkWorkerSpec is the topology specification for TiSpark slave nodes +type TiSparkWorkerSpec struct { + Host string `yaml:"host"` + SSHPort int `yaml:"ssh_port,omitempty"` + Imported bool `yaml:"imported,omitempty"` + Port int `yaml:"port" default:"7078"` + WebPort int `yaml:"web_port" default:"8081"` + DeployDir string `yaml:"deploy_dir,omitempty"` + Arch string `yaml:"arch,omitempty"` + OS string `yaml:"os,omitempty"` +} + +// Role returns the component role of the instance +func (s TiSparkWorkerSpec) Role() string { + return RoleTiSparkWorker +} + +// SSH returns the host and SSH port of the instance +func (s TiSparkWorkerSpec) SSH() (string, int) { + return s.Host, s.SSHPort +} + +// GetMainPort returns the main port of the instance +func (s TiSparkWorkerSpec) GetMainPort() int { + return s.Port +} + +// IsImported returns if the node is imported from TiDB-Ansible +func (s TiSparkWorkerSpec) IsImported() bool { + return s.Imported +} + +// Status queries current status of the instance +func (s TiSparkWorkerSpec) Status(pdList ...string) string { + url := fmt.Sprintf("http://%s:%d/", s.Host, s.WebPort) + return statusByURL(url) +} + +// TiSparkMasterComponent represents TiSpark master component. +type TiSparkMasterComponent struct{ *Specification } + +// Name implements Component interface. +func (c *TiSparkMasterComponent) Name() string { + return ComponentTiSpark +} + +// Instances implements Component interface. +func (c *TiSparkMasterComponent) Instances() []Instance { + ins := make([]Instance, 0, len(c.TiSparkMasters)) + for _, s := range c.TiSparkMasters { + ins = append(ins, &TiSparkMasterInstance{ + instance: instance{ + InstanceSpec: s, + name: c.Name(), + host: s.Host, + port: s.Port, + sshp: s.SSHPort, + topo: c.Specification, + + usedPorts: []int{ + s.Port, + s.WebPort, + }, + usedDirs: []string{ + s.DeployDir, + }, + statusFn: s.Status, + }, + }) + } + return ins +} + +// TiSparkMasterInstance represent the TiSpark master instance +type TiSparkMasterInstance struct { + instance +} + +// GetCustomFields get custom spark configs of the instance +func (i *TiSparkMasterInstance) GetCustomFields() map[string]interface{} { + v := reflect.ValueOf(i.InstanceSpec).FieldByName("SparkConfigs") + if !v.IsValid() { + return nil + } + return v.Interface().(map[string]interface{}) +} + +// GetCustomEnvs get custom spark envionment variables of the instance +func (i *TiSparkMasterInstance) GetCustomEnvs() map[string]string { + v := reflect.ValueOf(i.InstanceSpec).FieldByName("SparkEnvs") + if !v.IsValid() { + return nil + } + return v.Interface().(map[string]string) +} + +// InitConfig implement Instance interface +func (i *TiSparkMasterInstance) InitConfig(e executor.Executor, clusterName, clusterVersion, deployUser string, paths meta.DirPaths) error { + // generate systemd service to invoke spark's start/stop scripts + comp := i.Role() + host := i.GetHost() + port := i.GetPort() + sysCfg := filepath.Join(paths.Cache, fmt.Sprintf("%s-%s-%d.service", comp, host, port)) + + systemCfg := system.NewTiSparkConfig(comp, deployUser, paths.Deploy) + + if err := systemCfg.ConfigToFile(sysCfg); err != nil { + return errors.Trace(err) + } + tgt := filepath.Join("/tmp", comp+"_"+uuid.New().String()+".service") + if err := e.Transfer(sysCfg, tgt, false); err != nil { + return errors.Annotatef(err, "transfer from %s to %s failed", sysCfg, tgt) + } + cmd := fmt.Sprintf("mv %s /etc/systemd/system/%s-%d.service", tgt, comp, port) + if _, _, err := e.Execute(cmd, true); err != nil { + return errors.Annotatef(err, "execute: %s", cmd) + } + + // transfer default config + pdList := make([]string, 0) + for _, pd := range i.instance.topo.Endpoints(deployUser) { + pdList = append(pdList, fmt.Sprintf("%s:%d", pd.IP, pd.ClientPort)) + } + masterList := make([]string, 0) + for _, master := range i.instance.topo.TiSparkMasters { + masterList = append(masterList, fmt.Sprintf("%s:%d", master.Host, master.Port)) + } + + cfg := config.NewTiSparkConfig(pdList).WithMasters(strings.Join(masterList, ",")). + WithCustomFields(i.GetCustomFields()) + // transfer spark-defaults.conf + fp := filepath.Join(paths.Cache, fmt.Sprintf("spark-defaults-%s-%d.conf", host, port)) + if err := cfg.ConfigToFile(fp); err != nil { + return err + } + dst := filepath.Join(paths.Deploy, "conf", "spark-defaults.conf") + if err := e.Transfer(fp, dst, false); err != nil { + return err + } + + env := scripts.NewTiSparkEnv(host). + WithMasterPorts(i.usedPorts[0], i.usedPorts[1]). + WithCustomEnv(i.GetCustomEnvs()) + // transfer spark-env.sh file + fp = filepath.Join(paths.Cache, fmt.Sprintf("spark-env-%s-%d.sh", host, port)) + if err := env.ScriptToFile(fp); err != nil { + return err + } + // tispark files are all in a "spark" sub-directory of deploy dir + dst = filepath.Join(paths.Deploy, "conf", "spark-env.sh") + if err := e.Transfer(fp, dst, false); err != nil { + return err + } + + // transfer log4j config (it's not a template but a static file) + fp = filepath.Join(paths.Cache, fmt.Sprintf("spark-log4j-%s-%d.properties", host, port)) + log4jFile, err := config.GetConfig("spark-log4j.properties.tpl") + if err != nil { + return err + } + if err := ioutil.WriteFile(fp, log4jFile, 0644); err != nil { + return err + } + dst = filepath.Join(paths.Deploy, "conf", "log4j.properties") + return e.Transfer(fp, dst, false) +} + +// ScaleConfig deploy temporary config on scaling +func (i *TiSparkMasterInstance) ScaleConfig(e executor.Executor, cluster *Specification, + clusterName, clusterVersion, deployUser string, paths meta.DirPaths) error { + s := i.instance.topo + defer func() { i.instance.topo = s }() + i.instance.topo = cluster.Merge(i.instance.topo) + return i.InitConfig(e, clusterName, clusterVersion, deployUser, paths) +} + +// TiSparkWorkerComponent represents TiSpark slave component. +type TiSparkWorkerComponent struct{ *Specification } + +// Name implements Component interface. +func (c *TiSparkWorkerComponent) Name() string { + return ComponentTiSpark +} + +// Instances implements Component interface. +func (c *TiSparkWorkerComponent) Instances() []Instance { + ins := make([]Instance, 0, len(c.TiSparkWorkers)) + for _, s := range c.TiSparkWorkers { + ins = append(ins, &TiSparkWorkerInstance{ + instance: instance{ + InstanceSpec: s, + name: c.Name(), + host: s.Host, + port: s.Port, + sshp: s.SSHPort, + topo: c.Specification, + + usedPorts: []int{ + s.Port, + s.WebPort, + }, + usedDirs: []string{ + s.DeployDir, + }, + statusFn: s.Status, + }, + }) + } + return ins +} + +// TiSparkWorkerInstance represent the TiSpark slave instance +type TiSparkWorkerInstance struct { + instance +} + +// InitConfig implement Instance interface +func (i *TiSparkWorkerInstance) InitConfig(e executor.Executor, clusterName, clusterVersion, deployUser string, paths meta.DirPaths) error { + // generate systemd service to invoke spark's start/stop scripts + comp := i.Role() + host := i.GetHost() + port := i.GetPort() + sysCfg := filepath.Join(paths.Cache, fmt.Sprintf("%s-%s-%d.service", comp, host, port)) + + systemCfg := system.NewTiSparkConfig(comp, deployUser, paths.Deploy) + + if err := systemCfg.ConfigToFile(sysCfg); err != nil { + return errors.Trace(err) + } + tgt := filepath.Join("/tmp", comp+"_"+uuid.New().String()+".service") + if err := e.Transfer(sysCfg, tgt, false); err != nil { + return errors.Annotatef(err, "transfer from %s to %s failed", sysCfg, tgt) + } + cmd := fmt.Sprintf("mv %s /etc/systemd/system/%s-%d.service", tgt, comp, port) + if _, _, err := e.Execute(cmd, true); err != nil { + return errors.Annotatef(err, "execute: %s", cmd) + } + + // transfer default config + pdList := make([]string, 0) + for _, pd := range i.instance.topo.Endpoints(deployUser) { + pdList = append(pdList, fmt.Sprintf("%s:%d", pd.IP, pd.ClientPort)) + } + masterList := make([]string, 0) + for _, master := range i.instance.topo.TiSparkMasters { + masterList = append(masterList, fmt.Sprintf("%s:%d", master.Host, master.Port)) + } + + cfg := config.NewTiSparkConfig(pdList).WithMasters(strings.Join(masterList, ",")). + WithCustomFields(i.instance.topo.TiSparkMasters[0].SparkConfigs) + // transfer spark-defaults.conf + fp := filepath.Join(paths.Cache, fmt.Sprintf("spark-defaults-%s-%d.conf", host, port)) + if err := cfg.ConfigToFile(fp); err != nil { + return err + } + dst := filepath.Join(paths.Deploy, "conf", "spark-defaults.conf") + if err := e.Transfer(fp, dst, false); err != nil { + return err + } + + env := scripts.NewTiSparkEnv(i.topo.TiSparkMasters[0].Host). + WithMasterPorts(i.topo.TiSparkMasters[0].Port, i.topo.TiSparkMasters[0].WebPort). + WithWorkerPorts(i.usedPorts[0], i.usedPorts[1]). + WithCustomEnv(i.instance.topo.TiSparkMasters[0].SparkEnvs) + // transfer spark-env.sh file + fp = filepath.Join(paths.Cache, fmt.Sprintf("spark-env-%s-%d.sh", host, port)) + if err := env.ScriptToFile(fp); err != nil { + return err + } + // tispark files are all in a "spark" sub-directory of deploy dir + dst = filepath.Join(paths.Deploy, "conf", "spark-env.sh") + if err := e.Transfer(fp, dst, false); err != nil { + return err + } + + // transfer start-slave.sh + fp = filepath.Join(paths.Cache, fmt.Sprintf("start-tispark-slave-%s-%d.sh", host, port)) + slaveSh, err := env.SlaveScriptWithTemplate() + if err != nil { + return err + } + if err := ioutil.WriteFile(fp, slaveSh, 0755); err != nil { + return err + } + dst = filepath.Join(paths.Deploy, "sbin", "start-slave.sh") + if err := e.Transfer(fp, dst, false); err != nil { + return err + } + + // transfer log4j config (it's not a template but a static file) + fp = filepath.Join(paths.Cache, fmt.Sprintf("spark-log4j-%s-%d.properties", host, port)) + log4jFile, err := config.GetConfig("spark-log4j.properties.tpl") + if err != nil { + return err + } + if err := ioutil.WriteFile(fp, log4jFile, 0644); err != nil { + return err + } + dst = filepath.Join(paths.Deploy, "conf", "log4j.properties") + return e.Transfer(fp, dst, false) +} + +// ScaleConfig deploy temporary config on scaling +func (i *TiSparkWorkerInstance) ScaleConfig(e executor.Executor, cluster *Specification, + clusterName, clusterVersion, deployUser string, paths meta.DirPaths) error { + s := i.instance.topo + defer func() { i.instance.topo = s }() + i.instance.topo = cluster.Merge(i.instance.topo) + return i.InitConfig(e, clusterName, clusterVersion, deployUser, paths) +} diff --git a/pkg/cluster/spec/util.go b/pkg/cluster/spec/util.go index dc007e5667..05c66dd44b 100644 --- a/pkg/cluster/spec/util.go +++ b/pkg/cluster/spec/util.go @@ -57,7 +57,13 @@ func ClusterMetadata(clusterName string) (*ClusterMeta, error) { var cm ClusterMeta err := GetSpecManager().Metadata(clusterName, &cm) if err != nil { - return nil, errors.AddStack(err) + // Return the value of cm even on error, to make sure the caller can get the data + // we read, if there's any. + // This is necessary when, either by manual editing of meta.yaml file, by not fully + // validated `edit-config`, or by some unexpected operations from a broken legacy + // release, we could provide max possibility that operations like `display`, `scale` + // and `destroy` are still (more or less) working, by ignoring certain errors. + return &cm, errors.AddStack(err) } return &cm, nil diff --git a/pkg/cluster/task/builder.go b/pkg/cluster/task/builder.go index 8702a686c5..96308fc923 100644 --- a/pkg/cluster/task/builder.go +++ b/pkg/cluster/task/builder.go @@ -14,6 +14,9 @@ package task import ( + "fmt" + "path/filepath" + operator "github.com/pingcap/tiup/pkg/cluster/operation" "github.com/pingcap/tiup/pkg/cluster/spec" "github.com/pingcap/tiup/pkg/meta" @@ -135,13 +138,14 @@ func (b *Builder) Download(component, os, arch string, version string) *Builder // CopyComponent appends a CopyComponent task to the current task collection func (b *Builder) CopyComponent(component, os, arch string, version string, - dstHost, dstDir string, + srcPath, dstHost, dstDir string, ) *Builder { b.tasks = append(b.tasks, &CopyComponent{ component: component, os: os, arch: arch, version: version, + srcPath: srcPath, host: dstHost, dstDir: dstDir, }) @@ -324,6 +328,46 @@ func (b *Builder) CheckSys(host, dataDir, checkType string, topo *spec.Specifica return b } +// DeploySpark deployes spark as dependency of TiSpark +func (b *Builder) DeploySpark(inst spec.Instance, version, srcPath, deployDir string) *Builder { + sparkSubPath := spec.ComponentSubDir(spec.ComponentSpark, + spec.ComponentVersion(spec.ComponentSpark, version)) + return b.CopyComponent( + spec.ComponentSpark, + inst.OS(), + inst.Arch(), + spec.ComponentVersion(spec.ComponentSpark, version), + srcPath, + inst.GetHost(), + deployDir, + ).Shell( // spark is under a subdir, move it to deploy dir + inst.GetHost(), + fmt.Sprintf( + "cp -rf %[1]s %[2]s/ && cp -rf %[3]s/* %[2]s/ && rm -rf %[1]s %[3]s", + filepath.Join(deployDir, "bin", sparkSubPath), + deployDir, + filepath.Join(deployDir, sparkSubPath), + ), + false, // (not) sudo + ).CopyComponent( + inst.ComponentName(), + inst.OS(), + inst.Arch(), + version, + srcPath, + inst.GetHost(), + deployDir, + ).Shell( // move tispark jar to correct path + inst.GetHost(), + fmt.Sprintf( + "cp -f %[1]s/*.jar %[2]s/jars/ && rm -f %[1]s/*.jar", + filepath.Join(deployDir, "bin"), + deployDir, + ), + false, // (not) sudo + ) +} + // Parallel appends a parallel task to the current task collection func (b *Builder) Parallel(tasks ...Task) *Builder { b.tasks = append(b.tasks, &Parallel{inner: tasks}) diff --git a/pkg/cluster/task/copy_component.go b/pkg/cluster/task/copy_component.go index 08fd984641..e2465171e6 100644 --- a/pkg/cluster/task/copy_component.go +++ b/pkg/cluster/task/copy_component.go @@ -27,6 +27,7 @@ type CopyComponent struct { arch string version string host string + srcPath string dstDir string } @@ -35,7 +36,10 @@ func (c *CopyComponent) Execute(ctx *Context) error { // Copy to remote server resName := fmt.Sprintf("%s-%s", c.component, c.version) fileName := fmt.Sprintf("%s-%s-%s.tar.gz", resName, c.os, c.arch) - srcPath := spec.ProfilePath(spec.TiOpsPackageCacheDir, fileName) + srcPath := c.srcPath + if c.srcPath == "" { + srcPath = spec.ProfilePath(spec.TiOpsPackageCacheDir, fileName) + } install := &InstallPackage{ srcPath: srcPath, diff --git a/pkg/cluster/task/update_meta.go b/pkg/cluster/task/update_meta.go index c519774ca4..798c340949 100644 --- a/pkg/cluster/task/update_meta.go +++ b/pkg/cluster/task/update_meta.go @@ -83,6 +83,18 @@ func (u *UpdateMeta) Execute(ctx *Context) error { } newMeta.Topology.CDCServers = append(newMeta.Topology.CDCServers, topo.CDCServers[i]) } + for i, instance := range (&spec.TiSparkWorkerComponent{Specification: topo}).Instances() { + if deleted.Exist(instance.ID()) { + continue + } + newMeta.Topology.TiSparkWorkers = append(newMeta.Topology.TiSparkWorkers, topo.TiSparkWorkers[i]) + } + for i, instance := range (&spec.TiSparkMasterComponent{Specification: topo}).Instances() { + if deleted.Exist(instance.ID()) { + continue + } + newMeta.Topology.TiSparkMasters = append(newMeta.Topology.TiSparkMasters, topo.TiSparkMasters[i]) + } for i, instance := range (&spec.MonitorComponent{Specification: topo}).Instances() { if deleted.Exist(instance.ID()) { continue diff --git a/pkg/cluster/template/config/config.go b/pkg/cluster/template/config/config.go new file mode 100644 index 0000000000..dbee79584e --- /dev/null +++ b/pkg/cluster/template/config/config.go @@ -0,0 +1,26 @@ +// 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 config + +import ( + "path/filepath" + + "github.com/pingcap/tiup/pkg/cluster/embed" +) + +// GetConfig returns a raw config file from embed templates +func GetConfig(filename string) ([]byte, error) { + fp := filepath.Join("/templates", "config", filename) + return embed.ReadFile(fp) +} diff --git a/pkg/cluster/template/config/tispark.go b/pkg/cluster/template/config/tispark.go new file mode 100644 index 0000000000..a6a498bc15 --- /dev/null +++ b/pkg/cluster/template/config/tispark.go @@ -0,0 +1,81 @@ +// 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 config + +import ( + "bytes" + "io/ioutil" + "path/filepath" + "text/template" + + "github.com/pingcap/tiup/pkg/cluster/embed" +) + +// TiSparkConfig represent the data to generate TiSpark configs +type TiSparkConfig struct { + TiSparkMasters string + CustomFields map[string]interface{} + Endpoints []string +} + +// NewTiSparkConfig returns a TiSparkConfig +func NewTiSparkConfig(pds []string) *TiSparkConfig { + return &TiSparkConfig{Endpoints: pds} +} + +// WithMasters sets master address +func (c *TiSparkConfig) WithMasters(masters string) *TiSparkConfig { + c.TiSparkMasters = masters + return c +} + +// WithCustomFields sets custom setting fields +func (c *TiSparkConfig) WithCustomFields(m map[string]interface{}) *TiSparkConfig { + c.CustomFields = m + return c +} + +// Config generate the config file data. +func (c *TiSparkConfig) Config() ([]byte, error) { + fp := filepath.Join("/templates", "config", "spark-defaults.conf.tpl") + tpl, err := embed.ReadFile(fp) + if err != nil { + return nil, err + } + return c.ConfigWithTemplate(string(tpl)) +} + +// ConfigToFile write config content to specific path +func (c *TiSparkConfig) ConfigToFile(file string) error { + config, err := c.Config() + if err != nil { + return err + } + return ioutil.WriteFile(file, config, 0755) +} + +// ConfigWithTemplate parses the template file +func (c *TiSparkConfig) ConfigWithTemplate(tpl string) ([]byte, error) { + tmpl, err := template.New("TiSpark").Parse(tpl) + if err != nil { + return nil, err + } + + content := bytes.NewBufferString("") + if err := tmpl.Execute(content, c); err != nil { + return nil, err + } + + return content.Bytes(), nil +} diff --git a/pkg/cluster/template/scripts/scripts.go b/pkg/cluster/template/scripts/scripts.go new file mode 100644 index 0000000000..228fedc7b6 --- /dev/null +++ b/pkg/cluster/template/scripts/scripts.go @@ -0,0 +1,26 @@ +// 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 scripts + +import ( + "path/filepath" + + "github.com/pingcap/tiup/pkg/cluster/embed" +) + +// GetScript returns a raw config file from embed templates +func GetScript(filename string) ([]byte, error) { + fp := filepath.Join("/templates", "scripts", filename) + return embed.ReadFile(fp) +} diff --git a/pkg/cluster/template/scripts/tispark.go b/pkg/cluster/template/scripts/tispark.go new file mode 100644 index 0000000000..61ca1ca97f --- /dev/null +++ b/pkg/cluster/template/scripts/tispark.go @@ -0,0 +1,108 @@ +// 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 scripts + +import ( + "bytes" + "io/ioutil" + "text/template" +) + +// TiSparkEnv represent the data to generate TiSpark environment config +type TiSparkEnv struct { + TiSparkMaster string + MasterPort int + WorkerPort int + MasterUIPort int + WorkerUIPort int + CustomEnvs map[string]string +} + +// NewTiSparkEnv returns a TiSparkConfig +func NewTiSparkEnv(master string) *TiSparkEnv { + return &TiSparkEnv{TiSparkMaster: master} +} + +// WithCustomEnv sets custom setting fields +func (c *TiSparkEnv) WithCustomEnv(m map[string]string) *TiSparkEnv { + c.CustomEnvs = m + return c +} + +// WithMasterPorts sets port for masters +func (c *TiSparkEnv) WithMasterPorts(port, ui int) *TiSparkEnv { + c.MasterPort = port + c.MasterUIPort = ui + return c +} + +// WithWorkerPorts sets port for masters +func (c *TiSparkEnv) WithWorkerPorts(port, ui int) *TiSparkEnv { + c.WorkerPort = port + c.WorkerUIPort = ui + return c +} + +// Script generate the script file data. +func (c *TiSparkEnv) Script() ([]byte, error) { + tpl, err := GetScript("spark-env.sh.tpl") + if err != nil { + return nil, err + } + return c.ScriptWithTemplate(string(tpl)) +} + +// ScriptToFile write script content to specific path +func (c *TiSparkEnv) ScriptToFile(file string) error { + script, err := c.Script() + if err != nil { + return err + } + return ioutil.WriteFile(file, script, 0755) +} + +// ScriptWithTemplate parses the template file +func (c *TiSparkEnv) ScriptWithTemplate(tpl string) ([]byte, error) { + tmpl, err := template.New("TiSpark").Parse(tpl) + if err != nil { + return nil, err + } + + content := bytes.NewBufferString("") + if err := tmpl.Execute(content, c); err != nil { + return nil, err + } + + return content.Bytes(), nil +} + +// SlaveScriptWithTemplate parses the template file +func (c *TiSparkEnv) SlaveScriptWithTemplate() ([]byte, error) { + tpl, err := GetScript("start_tispark_slave.sh.tpl") + if err != nil { + return nil, err + } + + tmpl, err := template.New("TiSpark").Parse(string(tpl)) + if err != nil { + return nil, err + } + + content := bytes.NewBufferString("") + if err := tmpl.Execute(content, c); err != nil { + return nil, err + } + + return content.Bytes(), nil +} diff --git a/pkg/cluster/template/systemd/tispark.go b/pkg/cluster/template/systemd/tispark.go new file mode 100644 index 0000000000..38632b2572 --- /dev/null +++ b/pkg/cluster/template/systemd/tispark.go @@ -0,0 +1,82 @@ +// 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 system + +import ( + "bytes" + "io/ioutil" + "path" + "strings" + "text/template" + + "github.com/pingcap/tiup/pkg/cluster/embed" +) + +// TiSparkConfig represent the data to generate systemd config +type TiSparkConfig struct { + ServiceName string + User string + DeployDir string + // Takes one of no, on-success, on-failure, on-abnormal, on-watchdog, on-abort, or always. + // The Template set as always if this is not setted. + Restart string +} + +// NewTiSparkConfig returns a Config with given arguments +func NewTiSparkConfig(service, user, deployDir string) *TiSparkConfig { + if strings.Contains(service, "master") { + service = "master" + } else if strings.Contains(service, "worker") { + service = "slave" + } + return &TiSparkConfig{ + ServiceName: service, + User: user, + DeployDir: deployDir, + } +} + +// ConfigToFile write config content to specific path +func (c *TiSparkConfig) ConfigToFile(file string) error { + config, err := c.Config() + if err != nil { + return err + } + return ioutil.WriteFile(file, config, 0755) +} + +// Config generate the config file data. +func (c *TiSparkConfig) Config() ([]byte, error) { + fp := path.Join("/templates", "systemd", "tispark.service.tpl") + tpl, err := embed.ReadFile(fp) + if err != nil { + return nil, err + } + return c.ConfigWithTemplate(string(tpl)) +} + +// ConfigWithTemplate generate the system config content by tpl +func (c *TiSparkConfig) ConfigWithTemplate(tpl string) ([]byte, error) { + tmpl, err := template.New("system").Parse(tpl) + if err != nil { + return nil, err + } + + content := bytes.NewBufferString("") + if err := tmpl.Execute(content, c); err != nil { + return nil, err + } + + return content.Bytes(), nil +} diff --git a/pkg/utils/ioutil.go b/pkg/utils/ioutil.go index c801b6aacf..de13371662 100644 --- a/pkg/utils/ioutil.go +++ b/pkg/utils/ioutil.go @@ -16,6 +16,9 @@ package utils import ( "archive/tar" "compress/gzip" + "crypto/sha1" + "encoding/hex" + "fmt" "io" "os" "path" @@ -148,3 +151,54 @@ func Move(src, dst string) error { } return errors.Trace(os.RemoveAll(src)) } + +// CreateDir creates the directory if it not exists. +func CreateDir(path string) error { + if _, err := os.Stat(path); err != nil { + if os.IsNotExist(err) { + return os.MkdirAll(path, 0755) + } + return err + } + return nil +} + +// CopyFile copies a file from src to dst +func CopyFile(src, dst string) error { + in, err := os.Open(src) + if err != nil { + return err + } + defer in.Close() + + if IsExist(dst) { + return fmt.Errorf("destination path %s already exist", dst) + } + out, err := os.Create(dst) + if err != nil { + return err + } + defer out.Close() + + if _, err = io.Copy(out, in); err != nil { + return err + } + return nil +} + +// Checksum returns the sha1 sum of target file +func Checksum(file string) (string, error) { + tarball, err := os.OpenFile(file, os.O_RDONLY, 0) + if err != nil { + return "", err + } + defer tarball.Close() + + sha1Writter := sha1.New() + if _, err := io.Copy(sha1Writter, tarball); err != nil { + return "", err + } + + checksum := hex.EncodeToString(sha1Writter.Sum(nil)) + return checksum, nil +} diff --git a/pkg/utils/ioutils.go b/pkg/utils/ioutils.go deleted file mode 100644 index a76399e352..0000000000 --- a/pkg/utils/ioutils.go +++ /dev/null @@ -1,73 +0,0 @@ -// 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 utils - -import ( - "crypto/sha1" - "encoding/hex" - "fmt" - "io" - "os" -) - -// CreateDir creates the directory if it not exists. -func CreateDir(path string) error { - if _, err := os.Stat(path); err != nil { - if os.IsNotExist(err) { - return os.MkdirAll(path, 0755) - } - return err - } - return nil -} - -// CopyFile copies a file from src to dst -func CopyFile(src, dst string) error { - in, err := os.Open(src) - if err != nil { - return err - } - defer in.Close() - - if _, err := os.Stat(dst); !os.IsNotExist(err) { - return fmt.Errorf("destination path %s already exist", dst) - } - out, err := os.Create(dst) - if err != nil { - return err - } - defer out.Close() - - if _, err = io.Copy(out, in); err != nil { - return err - } - return nil -} - -// Checksum returns the sha1 sum of target file -func Checksum(file string) (string, error) { - tarball, err := os.OpenFile(file, os.O_RDONLY, 0) - if err != nil { - return "", err - } - defer tarball.Close() - - sha1Writter := sha1.New() - if _, err := io.Copy(sha1Writter, tarball); err != nil { - return "", err - } - - checksum := hex.EncodeToString(sha1Writter.Sum(nil)) - return checksum, nil -} diff --git a/templates/config/spark-defaults.conf.tpl b/templates/config/spark-defaults.conf.tpl new file mode 100644 index 0000000000..8e2b9c6791 --- /dev/null +++ b/templates/config/spark-defaults.conf.tpl @@ -0,0 +1,44 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Default system properties included when running spark-submit. +# This is useful for setting default environmental settings. + +# Example: +#spark.eventLog.dir: "hdfs://namenode:8021/directory" +# spark.executor.extraJavaOptions -XX:+PrintGCDetails -Dkey=value -Dnumbers="one two three" + +{{- define "PDList"}} + {{- range $idx, $pd := .}} + {{- if eq $idx 0}} + {{- $pd}} + {{- else -}} + ,{{$pd}} + {{- end}} + {{- end}} +{{- end}} + +{{ range $k, $v := .CustomFields}} +{{ $k }} {{ $v }} +{{- end }} +spark.sql.extensions org.apache.spark.sql.TiExtensions + +{{- if .TiSparkMasters}} +spark.master spark://{{.TiSparkMasters}} +{{- end}} + +spark.tispark.pd.addresses {{template "PDList" .Endpoints}} diff --git a/templates/config/spark-log4j.properties.tpl b/templates/config/spark-log4j.properties.tpl new file mode 100644 index 0000000000..d9d193670d --- /dev/null +++ b/templates/config/spark-log4j.properties.tpl @@ -0,0 +1,43 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Set everything to be logged to the console +log4j.rootCategory=INFO, console +log4j.appender.console=org.apache.log4j.ConsoleAppender +log4j.appender.console.target=System.err +log4j.appender.console.layout=org.apache.log4j.PatternLayout +log4j.appender.console.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss} %p %c{1}: %m%n + +# Set the default spark-shell log level to WARN. When running the spark-shell, the +# log level for this class is used to overwrite the root logger's log level, so that +# the user can have different defaults for the shell and regular Spark apps. +log4j.logger.org.apache.spark.repl.Main=WARN + +# Settings to quiet third party logs that are too verbose +log4j.logger.org.spark_project.jetty=WARN +log4j.logger.org.spark_project.jetty.util.component.AbstractLifeCycle=ERROR +log4j.logger.org.apache.spark.repl.SparkIMain$exprTyper=INFO +log4j.logger.org.apache.spark.repl.SparkILoop$SparkILoopInterpreter=INFO +log4j.logger.org.apache.parquet=ERROR +log4j.logger.parquet=ERROR + +# SPARK-9183: Settings to avoid annoying messages when looking up nonexistent UDFs in SparkSQL with Hive support +log4j.logger.org.apache.hadoop.hive.metastore.RetryingHMSHandler=FATAL +log4j.logger.org.apache.hadoop.hive.ql.exec.FunctionRegistry=ERROR + +# tispark disable "WARN ObjectStore:568 - Failed to get database" +log4j.logger.org.apache.hadoop.hive.metastore.ObjectStore=ERROR diff --git a/templates/scripts/spark-env.sh.tpl b/templates/scripts/spark-env.sh.tpl new file mode 100755 index 0000000000..330f46f934 --- /dev/null +++ b/templates/scripts/spark-env.sh.tpl @@ -0,0 +1,88 @@ +#!/usr/bin/env bash + +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# This file is sourced when running various Spark programs. +# Copy it as spark-env.sh and edit that to configure Spark for your site. + +# Options read when launching programs locally with +# ./bin/run-example or ./bin/spark-submit +# - HADOOP_CONF_DIR, to point Spark towards Hadoop configuration files +# - SPARK_LOCAL_IP, to set the IP address Spark binds to on this node +# - SPARK_PUBLIC_DNS, to set the public dns name of the driver program +# - SPARK_CLASSPATH, default classpath entries to append + +# Options read by executors and drivers running inside the cluster +# - SPARK_LOCAL_IP, to set the IP address Spark binds to on this node +# - SPARK_PUBLIC_DNS, to set the public DNS name of the driver program +# - SPARK_CLASSPATH, default classpath entries to append +# - SPARK_LOCAL_DIRS, storage directories to use on this node for shuffle and RDD data +# - MESOS_NATIVE_JAVA_LIBRARY, to point to your libmesos.so if you use Mesos + +# Options read in YARN client mode +# - HADOOP_CONF_DIR, to point Spark towards Hadoop configuration files +# - SPARK_EXECUTOR_INSTANCES, Number of executors to start (Default: 2) +# - SPARK_EXECUTOR_CORES, Number of cores for the executors (Default: 1). +# - SPARK_EXECUTOR_MEMORY, Memory per Executor (e.g. 1000M, 2G) (Default: 1G) +# - SPARK_DRIVER_MEMORY, Memory for Driver (e.g. 1000M, 2G) (Default: 1G) + +# Options for the daemons used in the standalone deploy mode +# - SPARK_MASTER_HOST, to bind the master to a different IP address or hostname +# - SPARK_MASTER_PORT / SPARK_MASTER_WEBUI_PORT, to use non-default ports for the master +# - SPARK_MASTER_OPTS, to set config properties only for the master (e.g. "-Dx=y") +# - SPARK_WORKER_CORES, to set the number of cores to use on this machine +# - SPARK_WORKER_MEMORY, to set how much total memory workers have to give executors (e.g. 1000m, 2g) +# - SPARK_WORKER_PORT / SPARK_WORKER_WEBUI_PORT, to use non-default ports for the worker +# - SPARK_WORKER_INSTANCES, to set the number of worker processes per node +# - SPARK_WORKER_DIR, to set the working directory of worker processes +# - SPARK_WORKER_OPTS, to set config properties only for the worker (e.g. "-Dx=y") +# - SPARK_DAEMON_MEMORY, to allocate to the master, worker and history server themselves (default: 1g). +# - SPARK_HISTORY_OPTS, to set config properties only for the history server (e.g. "-Dx=y") +# - SPARK_SHUFFLE_OPTS, to set config properties only for the external shuffle service (e.g. "-Dx=y") +# - SPARK_DAEMON_JAVA_OPTS, to set config properties for all daemons (e.g. "-Dx=y") +# - SPARK_PUBLIC_DNS, to set the public dns name of the master or workers + +# Generic options for the daemons used in the standalone deploy mode +# - SPARK_CONF_DIR Alternate conf dir. (Default: ${SPARK_HOME}/conf) +# - SPARK_LOG_DIR Where log files are stored. (Default: ${SPARK_HOME}/logs) +# - SPARK_PID_DIR Where the pid file is stored. (Default: /tmp) +# - SPARK_IDENT_STRING A string representing this instance of spark. (Default: $USER) +# - SPARK_NICENESS The scheduling priority for daemons. (Default: 0) +# - SPARK_NO_DAEMONIZE Run the proposed command in the foreground. It will not output a PID file. + +#export JAVA_HOME, to set jdk home + +{{ range $k, $v := .CustomEnvs}} +{{ $k }}={{ $v }} +{{- end }} + +{{- if .TiSparkMaster}} +SPARK_MASTER_HOST={{.TiSparkMaster}} +{{- end}} +{{- if ne .MasterPort 0}} +SPARK_MASTER_PORT={{.MasterPort}} +{{- end}} +{{- if ne .MasterUIPort 0}} +SPARK_MASTER_WEBUI_PORT={{.MasterUIPort}} +{{- end}} +{{- if ne .WorkerPort 0}} +SPARK_WORKER_PORT={{.WorkerPort}} +{{- end}} +{{- if ne .WorkerUIPort 0}} +SPARK_WORKER_WEBUI_PORT={{.WorkerUIPort}} +{{- end}} diff --git a/templates/scripts/start_tispark_slave.sh.tpl b/templates/scripts/start_tispark_slave.sh.tpl new file mode 100755 index 0000000000..b46556899f --- /dev/null +++ b/templates/scripts/start_tispark_slave.sh.tpl @@ -0,0 +1,94 @@ +#!/usr/bin/env bash + +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Starts a slave on the machine this script is executed on. +# +# Environment Variables +# +# SPARK_WORKER_INSTANCES The number of worker instances to run on this +# slave. Default is 1. +# SPARK_WORKER_PORT The base port number for the first worker. If set, +# subsequent workers will increment this number. If +# unset, Spark will find a valid port number, but +# with no guarantee of a predictable pattern. +# SPARK_WORKER_WEBUI_PORT The base port for the web interface of the first +# worker. Subsequent workers will increment this +# number. Default is 8081. + +if [ -z "${SPARK_HOME}" ]; then + export SPARK_HOME="$(cd "`dirname "$0"`"/..; pwd)" +fi + +# NOTE: This exact class name is matched downstream by SparkSubmit. +# Any changes need to be reflected there. +CLASS="org.apache.spark.deploy.worker.Worker" + +if [[ "$@" = *--help ]] || [[ "$@" = *-h ]]; then + echo "Usage: ./sbin/start-slave.sh [options] " + pattern="Usage:" + pattern+="\|Using Spark's default log4j profile:" + pattern+="\|Registered signal handlers for" + + "${SPARK_HOME}"/bin/spark-class $CLASS --help 2>&1 | grep -v "$pattern" 1>&2 + exit 1 +fi + +. "${SPARK_HOME}/sbin/spark-config.sh" + +. "${SPARK_HOME}/bin/load-spark-env.sh" + +# First argument should be the master; we need to store it aside because we may +# need to insert arguments between it and the other arguments + +{{- if .TiSparkMaster}} +MASTER=spark://{{.TiSparkMaster}}:{{.MasterPort}} +shift +{{- end}} + +# Determine desired worker port +if [ "$SPARK_WORKER_WEBUI_PORT" = "" ]; then + SPARK_WORKER_WEBUI_PORT=8081 +fi + +# Start up the appropriate number of workers on this machine. +# quick local function to start a worker +function start_instance { + WORKER_NUM=$1 + shift + + if [ "$SPARK_WORKER_PORT" = "" ]; then + PORT_FLAG= + PORT_NUM= + else + PORT_FLAG="--port" + PORT_NUM=$(( $SPARK_WORKER_PORT + $WORKER_NUM - 1 )) + fi + WEBUI_PORT=$(( $SPARK_WORKER_WEBUI_PORT + $WORKER_NUM - 1 )) + + "${SPARK_HOME}/sbin"/spark-daemon.sh start $CLASS $WORKER_NUM \ + --webui-port "$WEBUI_PORT" $PORT_FLAG $PORT_NUM $MASTER "$@" +} + +if [ "$SPARK_WORKER_INSTANCES" = "" ]; then + start_instance 1 "$@" +else + for ((i=0; i<$SPARK_WORKER_INSTANCES; i++)); do + start_instance $(( 1 + $i )) "$@" + done +fi diff --git a/templates/systemd/tispark.service.tpl b/templates/systemd/tispark.service.tpl new file mode 100644 index 0000000000..80e0624699 --- /dev/null +++ b/templates/systemd/tispark.service.tpl @@ -0,0 +1,19 @@ +[Unit] +Description={{.ServiceName}} service +After=syslog.target network.target remote-fs.target nss-lookup.target + +[Service] +User={{.User}} +ExecStart={{.DeployDir}}/sbin/start-{{.ServiceName}}.sh +ExecStop={{.DeployDir}}/sbin/stop-{{.ServiceName}}.sh +Type=forking +{{- if .Restart}} +Restart={{.Restart}} +{{else}} +Restart=always +{{end}} +RestartSec=15s +SendSIGKILL=no + +[Install] +WantedBy=multi-user.target diff --git a/tests/Makefile b/tests/Makefile index 4901189887..f7e6bd10c6 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,5 +1,3 @@ -.PHONY: server - build_integration_test: build_tiup_playground_test build_tiup_cluster_test build_tiup_dm_test build_tiup_playground_test: failpoint-enable @@ -24,4 +22,4 @@ build_tiup_test: failpoint-enable $(GOTEST) -c -cover -covermode=count \ -coverpkg=github.com/pingcap/tiup/... \ -o tests/tiup/bin/tiup.test \ - github.com/pingcap/tiup; \ No newline at end of file + github.com/pingcap/tiup; diff --git a/tests/tiup-cluster/run.sh b/tests/tiup-cluster/run.sh index 67fcd34ae4..84e26c3b62 100755 --- a/tests/tiup-cluster/run.sh +++ b/tests/tiup-cluster/run.sh @@ -10,8 +10,8 @@ PATH=$PATH:/tiup-cluster/bin export TIUP_CLUSTER_PROGRESS_REFRESH_RATE=10s export TIUP_CLUSTER_EXECUTE_DEFAULT_TIMEOUT=300s -export version=${version-v4.0.0} -export old_version=${old_version-v3.0.12} +export version=${version-v4.0.2} +export old_version=${old_version-v3.0.16} export dm_version=${dm_version-nightly} function tiup-cluster() { diff --git a/tests/tiup-cluster/script/cmd_subtest.sh b/tests/tiup-cluster/script/cmd_subtest.sh index 5fb7251a28..5ef162ff0a 100755 --- a/tests/tiup-cluster/script/cmd_subtest.sh +++ b/tests/tiup-cluster/script/cmd_subtest.sh @@ -49,50 +49,56 @@ function cmd_subtest() { tiup-cluster display $name if [ $test_cdc = true ]; then - totol_sub_one=19 + total_sub_one=21 else - totol_sub_one=16 + total_sub_one=18 fi echo "start scale in tidb" tiup-cluster --yes scale-in $name -N 172.19.0.101:4000 - wait_instance_num_reach $name $totol_sub_one + wait_instance_num_reach $name $total_sub_one echo "start scale out tidb" tiup-cluster --yes scale-out $name ./topo/full_scale_in_tidb.yaml # echo "start scale in tikv" # tiup-cluster --yes scale-in $name -N 172.19.0.103:20160 - # wait_instance_num_reach $name $totol_sub_one + # wait_instance_num_reach $name $total_sub_one # echo "start scale out tikv" # tiup-cluster --yes scale-out $name ./topo/full_scale_in_tikv.yaml echo "start scale in pd" tiup-cluster --yes scale-in $name -N 172.19.0.103:2379 - wait_instance_num_reach $name $totol_sub_one + wait_instance_num_reach $name $total_sub_one echo "start scale out pd" tiup-cluster --yes scale-out $name ./topo/full_scale_in_pd.yaml echo "start scale in pump" tiup-cluster --yes scale-in $name -N 172.19.0.103:8250 - wait_instance_num_reach $name $totol_sub_one + wait_instance_num_reach $name $total_sub_one echo "start scale out pump" tiup-cluster --yes scale-out $name ./topo/full_scale_in_pump.yaml if [ $test_cdc = "true" ]; then echo "start scale in cdc" yes | tiup-cluster scale-in $name -N 172.19.0.103:8300 - wait_instance_num_reach $name $totol_sub_one + wait_instance_num_reach $name $total_sub_one echo "start scale out cdc" yes | tiup-cluster scale-out $name ./topo/full_scale_in_cdc.yaml fi + echo "start scale in tispark" + yes | tiup-cluster --yes scale-in $name -N 172.19.0.104:7078 + wait_instance_num_reach $name $total_sub_one + echo "start scale out tispark" + yes | tiup-cluster --yes scale-out $name ./topo/full_scale_in_tispark.yaml + echo "start scale in grafana" tiup-cluster --yes scale-in $name -N 172.19.0.101:3000 - wait_instance_num_reach $name $totol_sub_one + wait_instance_num_reach $name $total_sub_one echo "start scale out grafana" tiup-cluster --yes scale-out $name ./topo/full_scale_in_grafana.yaml tiup-cluster _test $name writable tiup-cluster --yes destroy $name -} \ No newline at end of file +} diff --git a/tests/tiup-cluster/test_cmd.sh b/tests/tiup-cluster/test_cmd.sh index 36b9e62ad2..c056a2b054 100755 --- a/tests/tiup-cluster/test_cmd.sh +++ b/tests/tiup-cluster/test_cmd.sh @@ -4,8 +4,8 @@ set -eu source script/cmd_subtest.sh -echo "test cluster for verision v4.0.0-rc" -cmd_subtest v4.0.0-rc true +echo "test cluster for verision v4.0.0" +cmd_subtest v4.0.0 true -echo "test cluster for verision v4.0.0-rc.1" -cmd_subtest v4.0.0-rc.1 false +echo "test cluster for verision v4.0.2" +cmd_subtest v4.0.2 false diff --git a/tests/tiup-cluster/test_upgrade.sh b/tests/tiup-cluster/test_upgrade.sh index 81f23dc084..2b255f49b3 100755 --- a/tests/tiup-cluster/test_upgrade.sh +++ b/tests/tiup-cluster/test_upgrade.sh @@ -2,7 +2,7 @@ set -eu -version=${version-v4.0.0} +version=${version-v4.0.2} old_version=${old_version-v4.0.0-beta.2} name=test_upgrade topo=./topo/upgrade.yaml diff --git a/tests/tiup-cluster/topo/full.yaml b/tests/tiup-cluster/topo/full.yaml index eb8c6ec569..31a569c3ff 100644 --- a/tests/tiup-cluster/topo/full.yaml +++ b/tests/tiup-cluster/topo/full.yaml @@ -50,6 +50,12 @@ cdc_servers: - host: 172.19.0.104 - host: 172.19.0.105 +tispark_masters: + - host: 172.19.0.103 + +tispark_workers: + - host: 172.19.0.104 + monitoring_servers: - host: 172.19.0.101 grafana_servers: diff --git a/tests/tiup-cluster/topo/full_scale_in_tispark.yaml b/tests/tiup-cluster/topo/full_scale_in_tispark.yaml new file mode 100644 index 0000000000..2353220ac2 --- /dev/null +++ b/tests/tiup-cluster/topo/full_scale_in_tispark.yaml @@ -0,0 +1,2 @@ +tispark_workers: + - host: 172.19.0.105 diff --git a/tests/tiup-cluster/topo/full_without_cdc.yaml b/tests/tiup-cluster/topo/full_without_cdc.yaml index 3da417fdb4..b7830941df 100644 --- a/tests/tiup-cluster/topo/full_without_cdc.yaml +++ b/tests/tiup-cluster/topo/full_without_cdc.yaml @@ -45,6 +45,12 @@ drainer_servers: config: syncer.db-type: "file" +tispark_masters: + - host: 172.19.0.103 + +tispark_workers: + - host: 172.19.0.104 + monitoring_servers: - host: 172.19.0.101 grafana_servers: diff --git a/tests/tiup-cluster/topology.yaml b/tests/tiup-cluster/topology.yaml index a27c23f816..57ea243a3e 100644 --- a/tests/tiup-cluster/topology.yaml +++ b/tests/tiup-cluster/topology.yaml @@ -14,4 +14,5 @@ tikv_servers: - host: 172.16.4.190 - host: 172.16.5.158 - host: 172.16.5.53 - - host: 172.16.4.102 \ No newline at end of file + - host: 172.16.4.102 +