diff --git a/dev-tools/mage/dmgbuilder.go b/dev-tools/mage/dmgbuilder.go index 06041c74533..47a1125a5a6 100644 --- a/dev-tools/mage/dmgbuilder.go +++ b/dev-tools/mage/dmgbuilder.go @@ -109,6 +109,11 @@ func (b *dmgBuilder) buildBeatPkg() error { // Copy files into the packaging root and set their mode. for _, f := range b.Files { + if f.Symlink { + // not supported, handling symlink in post/pre install scripts + continue + } + target := filepath.Join(beatPkgRoot, f.Target) if err := Copy(f.Source, target); err != nil { if f.SkipOnMissing && errors.Is(err, os.ErrNotExist) { diff --git a/dev-tools/mage/pkgtypes.go b/dev-tools/mage/pkgtypes.go index 5800d5b5c18..b7f7c7bbbee 100644 --- a/dev-tools/mage/pkgtypes.go +++ b/dev-tools/mage/pkgtypes.go @@ -108,6 +108,7 @@ type PackageFile struct { Dep func(PackageSpec) error `yaml:"-" hash:"-" json:"-"` // Dependency to invoke during Evaluate. Owner string `yaml:"owner,omitempty"` // File Owner, for user and group name (rpm only). SkipOnMissing bool `yaml:"skip_on_missing,omitempty"` // Prevents build failure if the file is missing. + Symlink bool `yaml:"symlink"` // Symlink marks file as a symlink pointing from target to source. } // OSArchNames defines the names of architectures for use in packages. @@ -476,6 +477,10 @@ func copyInstallScript(spec PackageSpec, script string, local *string) error { *local = strings.TrimSuffix(*local, ".tmpl") } + if strings.HasSuffix(*local, "."+spec.Name) { + *local = strings.TrimSuffix(*local, "."+spec.Name) + } + if err := spec.ExpandFile(script, createDir(*local)); err != nil { return errors.Wrap(err, "failed to copy install script to package dir") } @@ -539,6 +544,11 @@ func PackageZip(spec PackageSpec) error { // Add files to zip. for _, pkgFile := range spec.Files { + if pkgFile.Symlink { + // not supported on zip archives + continue + } + if err := addFileToZip(w, baseDir, pkgFile); err != nil { p, _ := filepath.Abs(pkgFile.Source) return errors.Wrapf(err, "failed adding file=%+v to zip", p) @@ -584,11 +594,32 @@ func PackageTarGz(spec PackageSpec) error { // Add files to tar. for _, pkgFile := range spec.Files { + if pkgFile.Symlink { + continue + } + if err := addFileToTar(w, baseDir, pkgFile); err != nil { return errors.Wrapf(err, "failed adding file=%+v to tar", pkgFile) } } + // same for symlinks so they can point to files in tar + for _, pkgFile := range spec.Files { + if !pkgFile.Symlink { + continue + } + + tmpdir, err := ioutil.TempDir("", "TmpSymlinkDropPath") + if err != nil { + return err + } + defer os.RemoveAll(tmpdir) + + if err := addSymlinkToTar(tmpdir, w, baseDir, pkgFile); err != nil { + return errors.Wrapf(err, "failed adding file=%+v to tar", pkgFile) + } + } + if err := w.Close(); err != nil { return err } @@ -882,6 +913,56 @@ func addFileToTar(ar *tar.Writer, baseDir string, pkgFile PackageFile) error { }) } +// addSymlinkToTar adds a symlink file to a tar archive. +func addSymlinkToTar(tmpdir string, ar *tar.Writer, baseDir string, pkgFile PackageFile) error { + // create symlink we can work with later, header will be updated later + link := filepath.Join(tmpdir, "link") + target := tmpdir + if err := os.Symlink(target, link); err != nil { + return err + } + + return filepath.Walk(link, func(path string, info os.FileInfo, err error) error { + if err != nil { + if pkgFile.SkipOnMissing && os.IsNotExist(err) { + return nil + } + + return err + } + + header, err := tar.FileInfoHeader(info, info.Name()) + if err != nil { + return err + } + header.Uname, header.Gname = "root", "root" + header.Uid, header.Gid = 0, 0 + + if info.Mode().IsRegular() && pkgFile.Mode > 0 { + header.Mode = int64(pkgFile.Mode & os.ModePerm) + } else if info.IsDir() { + header.Mode = int64(0755) + } + + header.Name = filepath.Join(baseDir, pkgFile.Target) + if filepath.IsAbs(pkgFile.Target) { + header.Name = pkgFile.Target + } + + header.Linkname = pkgFile.Source + header.Typeflag = tar.TypeSymlink + + if mg.Verbose() { + log.Println("Adding", os.FileMode(header.Mode), header.Name) + } + if err := ar.WriteHeader(header); err != nil { + return err + } + + return nil + }) +} + // PackageDMG packages the Beat into a .dmg file containing an installer pkg // and uninstaller app. func PackageDMG(spec PackageSpec) error { diff --git a/dev-tools/mage/settings.go b/dev-tools/mage/settings.go index f7de61e7db0..08a619c3df3 100644 --- a/dev-tools/mage/settings.go +++ b/dev-tools/mage/settings.go @@ -85,6 +85,7 @@ var ( "beat_doc_branch": BeatDocBranch, "beat_version": BeatQualifiedVersion, "commit": CommitHash, + "commit_short": CommitHashShort, "date": BuildDate, "elastic_beats_dir": ElasticBeatsDir, "go_version": GoVersion, @@ -239,6 +240,15 @@ func CommitHash() (string, error) { return commitHash, err } +// CommitHashShort returns the short length git commit hash. +func CommitHashShort() (string, error) { + shortHash, err := CommitHash() + if len(shortHash) > 6 { + shortHash = shortHash[:6] + } + return shortHash, err +} + var ( elasticBeatsDirValue string elasticBeatsDirErr error diff --git a/dev-tools/packaging/packages.yml b/dev-tools/packaging/packages.yml index f4261945233..2dcfba0f8a3 100644 --- a/dev-tools/packaging/packages.yml +++ b/dev-tools/packaging/packages.yml @@ -45,6 +45,10 @@ shared: source: 'elastic-agent.yml' mode: 0600 config: true + /etc/{{.BeatName}}/.elastic-agent.active.commit: + content: > + {{ commit }} + mode: 0644 /usr/share/{{.BeatName}}/bin/{{.BeatName}}-god: source: build/golang-crossbuild/god-{{.GOOS}}-{{.Platform.Arch}} mode: 0755 @@ -57,45 +61,48 @@ shared: /etc/init.d/{{.BeatServiceName}}: template: '{{ elastic_beats_dir }}/dev-tools/packaging/templates/{{.PackageType}}/init.sh.tmpl' mode: 0755 - /var/lib/{{.BeatName}}/downloads/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz: + /var/lib/{{.BeatName}}/data/{{.BeatName}}-{{ commit_short }}/{{.BeatName}}{{.BinaryExt}}: + source: build/golang-crossbuild/{{.BeatName}}-{{.GOOS}}-{{.Platform.Arch}}{{.BinaryExt}} + mode: 0644 + /var/lib/{{.BeatName}}/data/{{.BeatName}}-{{ commit_short }}/downloads/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz: source: '{{.AgentDropPath}}/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz' mode: 0644 - /var/lib/{{.BeatName}}/downloads/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512: + /var/lib/{{.BeatName}}/data/{{.BeatName}}-{{ commit_short }}/downloads/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512: source: '{{.AgentDropPath}}/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512' mode: 0644 - /var/lib/{{.BeatName}}/downloads/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc: + /var/lib/{{.BeatName}}/data/{{.BeatName}}-{{ commit_short }}/downloads/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc: source: '{{.AgentDropPath}}/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc' mode: 0644 skip_on_missing: true - /var/lib/{{.BeatName}}/downloads/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz: + /var/lib/{{.BeatName}}/data/{{.BeatName}}-{{ commit_short }}/downloads/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz: source: '{{.AgentDropPath}}/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz' mode: 0644 - /var/lib/{{.BeatName}}/downloads/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512: + /var/lib/{{.BeatName}}/data/{{.BeatName}}-{{ commit_short }}/downloads/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512: source: '{{.AgentDropPath}}/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512' mode: 0644 - /var/lib/{{.BeatName}}/downloads/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc: + /var/lib/{{.BeatName}}/data/{{.BeatName}}-{{ commit_short }}/downloads/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc: source: '{{.AgentDropPath}}/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc' mode: 0644 skip_on_missing: true - /var/lib/{{.BeatName}}/downloads/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz: + /var/lib/{{.BeatName}}/data/{{.BeatName}}-{{ commit_short }}/downloads/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz: source: '{{.AgentDropPath}}/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz' mode: 0644 - /var/lib/{{.BeatName}}/downloads/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512: + /var/lib/{{.BeatName}}/data/{{.BeatName}}-{{ commit_short }}/downloads/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512: source: '{{.AgentDropPath}}/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512' mode: 0644 - /var/lib/{{.BeatName}}/downloads/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc: + /var/lib/{{.BeatName}}/data/{{.BeatName}}-{{ commit_short }}/downloads/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc: source: '{{.AgentDropPath}}/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc' mode: 0644 skip_on_missing: true - /var/lib/{{.BeatName}}/downloads/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz: + /var/lib/{{.BeatName}}/data/{{.BeatName}}-{{ commit_short }}/downloads/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz: source: '{{.AgentDropPath}}/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz' mode: 0644 skip_on_missing: true - /var/lib/{{.BeatName}}/downloads/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512: + /var/lib/{{.BeatName}}/data/{{.BeatName}}-{{ commit_short }}/downloads/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512: source: '{{.AgentDropPath}}/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512' mode: 0644 skip_on_missing: true - /var/lib/{{.BeatName}}/downloads/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc: + /var/lib/{{.BeatName}}/data/{{.BeatName}}-{{ commit_short }}/downloads/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc: source: '{{.AgentDropPath}}/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc' mode: 0644 skip_on_missing: true @@ -112,7 +119,7 @@ shared: identifier: 'co.{{.BeatVendor | tolower}}.beats.{{.BeatName}}' install_path: /Library/Application Support pre_install_script: '{{ elastic_beats_dir }}/dev-tools/packaging/templates/darwin/scripts/preinstall.tmpl' - post_install_script: '{{ elastic_beats_dir }}/dev-tools/packaging/templates/darwin/scripts/postinstall.tmpl' + post_install_script: '{{ elastic_beats_dir }}/dev-tools/packaging/templates/darwin/scripts/postinstall.elastic-agent.tmpl' files: /Library/Application Support/{{.BeatVendor}}/{{.BeatName}}/bin/{{.BeatName}}{{.BinaryExt}}: source: build/golang-crossbuild/{{.BeatName}}-{{.GOOS}}-{{.Platform.Arch}}{{.BinaryExt}} @@ -140,47 +147,54 @@ shared: source: 'elastic-agent.yml' mode: 0600 config: true - /etc/{{.BeatName}}/data/downloads/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz: + /etc/{{.BeatName}}/.elastic-agent.active.commit: + content: > + {{ commit }} + mode: 0644 + /etc/{{.BeatName}}/data/{{.BeatName}}-{{ commit_short }}/{{.BeatName}}{{.BinaryExt}}: + source: build/golang-crossbuild/{{.BeatName}}-{{.GOOS}}-{{.Platform.Arch}}{{.BinaryExt}} + mode: 0755 + /etc/{{.BeatName}}/data/{{.BeatName}}-{{ commit_short }}/downloads/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz: source: '{{.AgentDropPath}}/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz' mode: 0644 - /etc/{{.BeatName}}/data/downloads/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512: + /etc/{{.BeatName}}/data/{{.BeatName}}-{{ commit_short }}/downloads/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512: source: '{{.AgentDropPath}}/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512' mode: 0644 skip_on_missing: true - /etc/{{.BeatName}}/data/downloads/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc: + /etc/{{.BeatName}}/data/{{.BeatName}}-{{ commit_short }}/downloads/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc: source: '{{.AgentDropPath}}/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc' mode: 0644 skip_on_missing: true - /etc/{{.BeatName}}/data/downloads/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz: + /etc/{{.BeatName}}/data/{{.BeatName}}-{{ commit_short }}/downloads/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz: source: '{{.AgentDropPath}}/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz' mode: 0644 - /etc/{{.BeatName}}/data/downloads/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512: + /etc/{{.BeatName}}/data/{{.BeatName}}-{{ commit_short }}/downloads/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512: source: '{{.AgentDropPath}}/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512' mode: 0644 skip_on_missing: true - /etc/{{.BeatName}}/data/downloads/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc: + /etc/{{.BeatName}}/data/{{.BeatName}}-{{ commit_short }}/downloads/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc: source: '{{.AgentDropPath}}/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc' mode: 0644 skip_on_missing: true - /etc/{{.BeatName}}/data/downloads/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz: + /etc/{{.BeatName}}/data/{{.BeatName}}-{{ commit_short }}/downloads/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz: source: '{{.AgentDropPath}}/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz' mode: 0644 - /etc/{{.BeatName}}/data/downloads/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512: + /etc/{{.BeatName}}/data/{{.BeatName}}-{{ commit_short }}/downloads/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512: source: '{{.AgentDropPath}}/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512' mode: 0644 - /etc/{{.BeatName}}/data/downloads/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc: + /etc/{{.BeatName}}/data/{{.BeatName}}-{{ commit_short }}/downloads/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc: source: '{{.AgentDropPath}}/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc' mode: 0644 skip_on_missing: true - /etc/{{.BeatName}}/data/downloads/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz: + /etc/{{.BeatName}}/data/{{.BeatName}}-{{ commit_short }}/downloads/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz: source: '{{.AgentDropPath}}/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz' mode: 0644 skip_on_missing: true - /etc/{{.BeatName}}/data/downloads/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512: + /etc/{{.BeatName}}/data/{{.BeatName}}-{{ commit_short }}/downloads/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512: source: '{{.AgentDropPath}}/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512' mode: 0644 skip_on_missing: true - /etc/{{.BeatName}}/data/downloads/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc: + /etc/{{.BeatName}}/data/{{.BeatName}}-{{ commit_short }}/downloads/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc: source: '{{.AgentDropPath}}/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc' mode: 0644 skip_on_missing: true @@ -189,6 +203,9 @@ shared: '{{.BeatName}}{{.BinaryExt}}': source: build/golang-crossbuild/{{.BeatName}}-{{.GOOS}}-{{.Platform.Arch}}{{.BinaryExt}} mode: 0755 + 'data/{{.BeatName}}-{{ commit_short }}/{{.BeatName}}{{.BinaryExt}}': + source: build/golang-crossbuild/{{.BeatName}}-{{.GOOS}}-{{.Platform.Arch}}{{.BinaryExt}} + mode: 0755 LICENSE.txt: source: '{{ repo.RootDir }}/LICENSE.txt' mode: 0644 @@ -209,51 +226,55 @@ shared: source: 'elastic-agent.yml' mode: 0600 config: true + '.elastic-agent.active.commit': + content: > + {{ commit }} + mode: 0644 # Binary package spec (tar.gz for linux/darwin) for community beats. - &agent_binary_spec <<: *common files: <<: *agent_binary_files - 'data/downloads/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz': + 'data/{{.BeatName}}-{{ commit_short }}/downloads/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz': source: '{{.AgentDropPath}}/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz' mode: 0644 - 'data/downloads/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512': + 'data/{{.BeatName}}-{{ commit_short }}/downloads/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512': source: '{{.AgentDropPath}}/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512' mode: 0644 - 'data/downloads/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc': + 'data/{{.BeatName}}-{{ commit_short }}/downloads/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc': source: '{{.AgentDropPath}}/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc' mode: 0644 skip_on_missing: true - 'data/downloads/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz': + 'data/{{.BeatName}}-{{ commit_short }}/downloads/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz': source: '{{.AgentDropPath}}/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz' mode: 0644 - 'data/downloads/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512': + 'data/{{.BeatName}}-{{ commit_short }}/downloads/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512': source: '{{.AgentDropPath}}/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512' mode: 0644 - 'data/downloads/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc': + 'data/{{.BeatName}}-{{ commit_short }}/downloads/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc': source: '{{.AgentDropPath}}/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc' mode: 0644 skip_on_missing: true - 'data/downloads/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz': + 'data/{{.BeatName}}-{{ commit_short }}/downloads/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz': source: '{{.AgentDropPath}}/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz' mode: 0644 - 'data/downloads/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512': + 'data/{{.BeatName}}-{{ commit_short }}/downloads/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512': source: '{{.AgentDropPath}}/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512' mode: 0644 - 'data/downloads/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc': + 'data/{{.BeatName}}-{{ commit_short }}/downloads/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc': source: '{{.AgentDropPath}}/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc' mode: 0644 skip_on_missing: true - 'data/downloads/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz': + 'data/{{.BeatName}}-{{ commit_short }}/downloads/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz': source: '{{.AgentDropPath}}/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz' mode: 0644 skip_on_missing: true - 'data/downloads/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512': + 'data/{{.BeatName}}-{{ commit_short }}/downloads/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512': source: '{{.AgentDropPath}}/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.sha512' mode: 0644 skip_on_missing: true - 'data/downloads/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc': + 'data/{{.BeatName}}-{{ commit_short }}/downloads/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc': source: '{{.AgentDropPath}}/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.tar.gz.asc' mode: 0644 skip_on_missing: true @@ -269,45 +290,45 @@ shared: uninstall-service-{{.BeatName}}.ps1: template: '{{ elastic_beats_dir }}/dev-tools/packaging/templates/windows/uninstall-service.ps1.tmpl' mode: 0755 - 'data/downloads/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip': + 'data/{{.BeatName}}-{{ commit_short }}/downloads/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip': source: '{{.AgentDropPath}}/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip' mode: 0644 - 'data/downloads/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip.sha512': + 'data/{{.BeatName}}-{{ commit_short }}/downloads/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip.sha512': source: '{{.AgentDropPath}}/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip.sha512' mode: 0644 - 'data/downloads/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip.asc': + 'data/{{.BeatName}}-{{ commit_short }}/downloads/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip.asc': source: '{{.AgentDropPath}}/filebeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip.asc' mode: 0644 skip_on_missing: true - 'data/downloads/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip': + 'data/{{.BeatName}}-{{ commit_short }}/downloads/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip': source: '{{.AgentDropPath}}/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip' mode: 0644 - 'data/downloads/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip.sha512': + 'data/{{.BeatName}}-{{ commit_short }}/downloads/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip.sha512': source: '{{.AgentDropPath}}/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip.sha512' mode: 0644 - 'data/downloads/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip.asc': + 'data/{{.BeatName}}-{{ commit_short }}/downloads/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip.asc': source: '{{.AgentDropPath}}/heartbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip.asc' mode: 0644 skip_on_missing: true - 'data/downloads/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip': + 'data/{{.BeatName}}-{{ commit_short }}/downloads/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip': source: '{{.AgentDropPath}}/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip' mode: 0644 - 'data/downloads/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip.sha512': + 'data/{{.BeatName}}-{{ commit_short }}/downloads/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip.sha512': source: '{{.AgentDropPath}}/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip.sha512' mode: 0644 - 'data/downloads/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip.asc': + 'data/{{.BeatName}}-{{ commit_short }}/downloads/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip.asc': source: '{{.AgentDropPath}}/metricbeat-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip.asc' mode: 0644 skip_on_missing: true - 'data/downloads/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip': + 'data/{{.BeatName}}-{{ commit_short }}/downloads/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip': source: '{{.AgentDropPath}}/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip' mode: 0644 skip_on_missing: true - 'data/downloads/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip.sha512': + 'data/{{.BeatName}}-{{ commit_short }}/downloads/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip.sha512': source: '{{.AgentDropPath}}/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip.sha512' mode: 0644 skip_on_missing: true - 'data/downloads/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip.asc': + 'data/{{.BeatName}}-{{ commit_short }}/downloads/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip.asc': source: '{{.AgentDropPath}}/endpoint-security-{{ beat_version }}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.GOOS}}-{{.AgentArchName}}.zip.asc' mode: 0644 skip_on_missing: true @@ -326,6 +347,10 @@ shared: source: 'elastic-agent.docker.yml' mode: 0600 config: true + '.elastic-agent.active.commit': + content: > + {{ commit }} + mode: 0644 # Deb/RPM spec for community beats. - &deb_rpm_spec @@ -779,7 +804,8 @@ specs: <<: *elastic_license_for_binaries files: '{{.BeatName}}{{.BinaryExt}}': - source: ./build/golang-crossbuild/{{.BeatName}}-{{.GOOS}}-{{.Platform.Arch}}{{.BinaryExt}} + source: data/{{.BeatName}}-{{ commit_short }}/{{.BeatName}}{{.BinaryExt}} + symlink: true - os: darwin types: [dmg] @@ -789,7 +815,8 @@ specs: files: /Library/Application Support/{{.BeatVendor}}/{{.BeatName}}/bin/{{.BeatName}}{{.BinaryExt}}: mode: 0755 - source: ./build/golang-crossbuild/{{.BeatName}}-{{.GOOS}}-{{.Platform.Arch}}{{.BinaryExt}} + source: /etc/{{.BeatName}}/data/{{.BeatName}}-{{ commit_short }}/{{.BeatName}}{{.BinaryExt}} + symlink: true - os: linux types: [tgz] @@ -798,7 +825,9 @@ specs: <<: *elastic_license_for_binaries files: '{{.BeatName}}{{.BinaryExt}}': - source: ./build/golang-crossbuild/{{.BeatName}}-{{.GOOS}}-{{.Platform.Arch}}{{.BinaryExt}} + source: data/{{.BeatName}}-{{ commit_short }}/{{.BeatName}}{{.BinaryExt}} + symlink: true + mode: 0755 - os: linux types: [deb, rpm] @@ -807,7 +836,8 @@ specs: <<: *elastic_license_for_deb_rpm files: /usr/share/{{.BeatName}}/bin/{{.BeatName}}{{.BinaryExt}}: - source: ./build/golang-crossbuild/{{.BeatName}}-{{.GOOS}}-{{.Platform.Arch}}{{.BinaryExt}} + source: /var/lib/{{.BeatName}}/data/{{.BeatName}}-{{ commit_short }}/{{.BeatName}}{{.BinaryExt}} + symlink: true - os: linux types: [docker] diff --git a/dev-tools/packaging/templates/darwin/scripts/postinstall.elastic-agent.tmpl b/dev-tools/packaging/templates/darwin/scripts/postinstall.elastic-agent.tmpl new file mode 100644 index 00000000000..2a9549b1d3e --- /dev/null +++ b/dev-tools/packaging/templates/darwin/scripts/postinstall.elastic-agent.tmpl @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +BEAT_NAME="{{.BeatName}}" +VERSION="{{.Version}}{{if .Snapshot}}-SNAPSHOT{{end}}" +SCRIPT="postinstall" +INSTALL_DIR="{{.install_path}}/{{.BeatVendor}}/{{.BeatName}}" +IDENTIFIER="{{.identifier}}" +VERSIONED_EXECUTABLE="/etc/{{.BeatName}}/data/{{.BeatName}}-{{ commit_short }}/{{.BeatName}}{{.BinaryExt}}" +EXE_ROOT="/Library/Application Support/{{.BeatVendor}}/{{.BeatName}}/bin" +EXE_NAME="{{.BeatName}}{{.BinaryExt}}" + +log() { + LEVEL="$1"; shift + syslog -s -l "$LEVEL" "$BEAT_NAME $SCRIPT: $@" +} + +die() { + log ERROR "Failed: $@" +} + +log WARN "identifier: $IDENTIFIER" +log WARN "version: $VERSION" +log WARN "install_dir: $INSTALL_DIR" + +mkdir -p "$EXE_ROOT" || die "Unable to create $BEAT_NAME bin directory" +ln -s "$VERSIONED_EXECUTABLE" "$EXE_ROOT/$EXE_NAME" || die "Unable to create $BEAT_NAME symlink" + +DAEMON_PLIST="/Library/LaunchDaemons/$IDENTIFIER.plist" +launchctl unload -w "$DAEMON_PLIST" +rm -f "$DAEMON_PLIST" +ln -s "$INSTALL_DIR/$IDENTIFIER.plist" "$DAEMON_PLIST" || die "Unable to create $DAEMON_PLIST symlink" +launchctl load -w "$DAEMON_PLIST" || die "Unable to install launchctl daemon $DAEMON_PLIST" diff --git a/dev-tools/packaging/templates/docker/Dockerfile.elastic-agent.tmpl b/dev-tools/packaging/templates/docker/Dockerfile.elastic-agent.tmpl index a7242baa73b..5e6c0fcd6cd 100644 --- a/dev-tools/packaging/templates/docker/Dockerfile.elastic-agent.tmpl +++ b/dev-tools/packaging/templates/docker/Dockerfile.elastic-agent.tmpl @@ -8,18 +8,20 @@ FROM {{ .buildFrom }} AS home COPY beat {{ $beatHome }} -RUN mkdir -p {{ $beatHome }}/data {{ $beatHome }}/logs && \ +RUN mkdir -p {{ $beatHome }}/data {{ $beatHome }}/data/elastic-agent-{{ commit_short }}/logs && \ chown -R root:root {{ $beatHome }} && \ find {{ $beatHome }} -type d -exec chmod 0750 {} \; && \ find {{ $beatHome }} -type f -exec chmod 0640 {} \; && \ - chmod 0750 {{ $beatBinary }} && \ + rm {{ $beatBinary }} && \ + ln -s {{ $beatHome }}/data/elastic-agent-{{ commit_short }}/elastic-agent {{ $beatBinary }} && \ + chmod 0750 {{ $beatHome }}/data/elastic-agent-*/elastic-agent && \ {{- if .linux_capabilities }} setcap {{ .linux_capabilities }} {{ $beatBinary }} && \ {{- end }} {{- range $i, $modulesd := .ModulesDirs }} chmod 0770 {{ $beatHome}}/{{ $modulesd }} && \ {{- end }} - chmod 0770 {{ $beatHome }}/data {{ $beatHome }}/logs + chmod 0770 {{ $beatHome }}/data {{ $beatHome }}/data/elastic-agent-{{ commit_short }}/logs FROM {{ .from }} diff --git a/x-pack/elastic-agent/pkg/agent/application/paths/paths.go b/x-pack/elastic-agent/pkg/agent/application/paths/paths.go index adb5850bfb4..d32be56657d 100644 --- a/x-pack/elastic-agent/pkg/agent/application/paths/paths.go +++ b/x-pack/elastic-agent/pkg/agent/application/paths/paths.go @@ -8,23 +8,77 @@ import ( "flag" "os" "path/filepath" + "runtime" + + "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/config" ) var ( - homePath string - configPath string - dataPath string - logsPath string + homePath string + configPath string + dataPath string + logsPath string + serviceName string ) func init() { - exePath := retrieveExecutablePath() + initialHome := initialHome() + + var homePathVar, configPathVar, dataPathVar, logsPathVar string fs := flag.CommandLine - fs.StringVar(&homePath, "path.home", exePath, "Agent root path") - fs.StringVar(&configPath, "path.config", exePath, "Config path is the directory Agent looks for its config file") - fs.StringVar(&dataPath, "path.data", filepath.Join(exePath, "data"), "Data path contains Agent managed binaries") - fs.StringVar(&logsPath, "path.logs", exePath, "Logs path contains Agent log output") + fs.StringVar(&homePathVar, "path.home", initialHome, "Agent root path") + fs.StringVar(&configPathVar, "path.config", initialHome, "Config path is the directory Agent looks for its config file") + fs.StringVar(&dataPathVar, "path.data", filepath.Join(initialHome, "data"), "Data path contains Agent managed binaries") + fs.StringVar(&logsPathVar, "path.logs", initialHome, "Logs path contains Agent log output") + + // avoid rewriting initialized values by flagSet later + homePath = homePathVar + configPath = configPathVar + dataPath = dataPathVar + logsPath = logsPathVar + + getOverrides() +} + +// UpdatePaths update paths based on changes in paths file. +func UpdatePaths() { + getOverrides() +} + +func getOverrides() { + type paths struct { + HomePath string `config:"path.home" yaml:"path.home"` + ConfigPath string `config:"path.config" yaml:"path.config"` + DataPath string `config:"path.data" yaml:"path.data"` + LogsPath string `config:"path.logs" yaml:"path.logs"` + ServiceName string `config:"path.service_name" yaml:"path.service_name"` + } + + defaults := &paths{ + HomePath: homePath, + ConfigPath: configPath, + DataPath: dataPath, + LogsPath: logsPath, + } + + pathsFile := filepath.Join(dataPath, "paths.yml") + rawConfig, err := config.LoadYAML(pathsFile) + if err != nil { + return + } + + rawConfig.Unpack(defaults) + homePath = defaults.HomePath + configPath = defaults.ConfigPath + dataPath = defaults.DataPath + logsPath = defaults.LogsPath + serviceName = defaults.ServiceName +} + +// ServiceName return predefined service name if defined by initial call. +func ServiceName() string { + return serviceName } // Home returns a directory where binary lives @@ -54,5 +108,19 @@ func retrieveExecutablePath() string { panic(err) } - return filepath.Dir(execPath) + evalPath, err := filepath.EvalSymlinks(execPath) + if err != nil { + panic(err) + } + + return filepath.Dir(evalPath) +} + +func initialHome() string { + exePath := retrieveExecutablePath() + if runtime.GOOS == "windows" { + return exePath + } + + return filepath.Dir(filepath.Dir(exePath)) // is two level up the executable (symlink evaluated) } diff --git a/x-pack/elastic-agent/pkg/agent/application/reexec/manager.go b/x-pack/elastic-agent/pkg/agent/application/reexec/manager.go index 4662b1c6230..b21bb9b8c46 100644 --- a/x-pack/elastic-agent/pkg/agent/application/reexec/manager.go +++ b/x-pack/elastic-agent/pkg/agent/application/reexec/manager.go @@ -12,7 +12,7 @@ import ( type ExecManager interface { // ReExec asynchronously re-executes command in the same PID and memory address // as the currently running application. - ReExec() + ReExec(argOverrides ...string) // ShutdownChan returns the shutdown channel the main function should use to // handle shutdown of the current running application. @@ -42,12 +42,12 @@ func NewManager(log *logger.Logger, exec string) ExecManager { } } -func (m *manager) ReExec() { +func (m *manager) ReExec(argOverrides ...string) { go func() { close(m.trigger) <-m.shutdown - if err := reexec(m.logger, m.exec); err != nil { + if err := reexec(m.logger, m.exec, argOverrides...); err != nil { // panic; because there is no going back, everything is shutdown panic(err) } diff --git a/x-pack/elastic-agent/pkg/agent/application/reexec/reexec.go b/x-pack/elastic-agent/pkg/agent/application/reexec/reexec.go index 4f3c24a7aa6..9265ba15266 100644 --- a/x-pack/elastic-agent/pkg/agent/application/reexec/reexec.go +++ b/x-pack/elastic-agent/pkg/agent/application/reexec/reexec.go @@ -15,11 +15,12 @@ import ( "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/core/logger" ) -func reexec(log *logger.Logger, executable string) error { +func reexec(log *logger.Logger, executable string, argOverrides ...string) error { // force log sync, before re-exec _ = log.Sync() args := []string{filepath.Base(executable)} args = append(args, os.Args[1:]...) + args = append(args, argOverrides...) return unix.Exec(executable, args, os.Environ()) } diff --git a/x-pack/elastic-agent/pkg/agent/application/reexec/reexec_windows.go b/x-pack/elastic-agent/pkg/agent/application/reexec/reexec_windows.go index b79172226cb..7f2f3230dc5 100644 --- a/x-pack/elastic-agent/pkg/agent/application/reexec/reexec_windows.go +++ b/x-pack/elastic-agent/pkg/agent/application/reexec/reexec_windows.go @@ -28,12 +28,13 @@ import ( // current process just exits. // // * Sub-process - As a sub-process a new child is spawned and the current process just exits. -func reexec(log *logger.Logger, executable string) error { +func reexec(log *logger.Logger, executable string, argOverrides ...string) error { svc, status, err := getService() if err == nil { // running as a service; spawn re-exec windows sub-process log.Infof("Running as Windows service %s; triggering service restart", svc.Name) args := []string{filepath.Base(executable), "reexec_windows", svc.Name, strconv.Itoa(int(status.ProcessId))} + args = append(args, argOverrides...) cmd := exec.Cmd{ Path: executable, Args: args, @@ -51,6 +52,7 @@ func reexec(log *logger.Logger, executable string) error { log.Infof("Running as Windows process; spawning new child process") args := []string{filepath.Base(executable)} args = append(args, os.Args[1:]...) + args = append(args, argOverrides...) cmd := exec.Cmd{ Path: executable, Args: args, diff --git a/x-pack/elastic-agent/pkg/agent/cmd/checks.go b/x-pack/elastic-agent/pkg/agent/cmd/checks.go new file mode 100644 index 00000000000..4fee7497009 --- /dev/null +++ b/x-pack/elastic-agent/pkg/agent/cmd/checks.go @@ -0,0 +1,57 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +// +build !windows + +package cmd + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + + "github.com/spf13/cobra" + + // import logp flags + _ "github.com/elastic/beats/v7/libbeat/logp/configure" + "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/application/paths" + "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/release" +) + +// preRunCheck is noop because +// - darwin.tar - symlink created during packaging +// - linux.tar - symlink created during packaging +// - linux.rpm - symlink created using install script +// - linux.deb - symlink created using install script +// - linux.docker - symlink created using Dockerfile +func preRunCheck(flags *globalFlags) func(cmd *cobra.Command, args []string) error { + return func(cmd *cobra.Command, args []string) error { + if sn := paths.ServiceName(); sn != "" { + // paths were created we're running as child. + return nil + } + + // get versioned path + smallHash := fmt.Sprintf("elastic-agent-%s", smallHash(release.Commit())) + commitFilepath := filepath.Join(paths.Config(), commitFile) // use other file in the future + if content, err := ioutil.ReadFile(commitFilepath); err == nil { + smallHash = hashedDirName(content) + } + + origExecPath, err := os.Executable() + if err != nil { + return err + } + reexecPath := filepath.Join(paths.Data(), smallHash, filepath.Base(origExecPath)) + + // generate paths + if err := generatePaths(filepath.Dir(reexecPath), origExecPath); err != nil { + return err + } + + paths.UpdatePaths() + return nil + } +} diff --git a/x-pack/elastic-agent/pkg/agent/cmd/checks_windows.go b/x-pack/elastic-agent/pkg/agent/cmd/checks_windows.go new file mode 100644 index 00000000000..36108c8e08b --- /dev/null +++ b/x-pack/elastic-agent/pkg/agent/cmd/checks_windows.go @@ -0,0 +1,114 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +// +build windows + +package cmd + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + + "github.com/spf13/cobra" + + // import logp flags + _ "github.com/elastic/beats/v7/libbeat/logp/configure" + + "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/application/paths" + "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/application/reexec" + "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/configuration" + "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/errors" + "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/config" + "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/core/logger" + "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/release" +) + +func preRunCheck(flags *globalFlags) func(cmd *cobra.Command, args []string) error { + return func(cmd *cobra.Command, args []string) error { + if sn := paths.ServiceName(); sn != "" { + // replacing with correct service name so we + // can talk to service manager. + if !filepath.IsAbs(os.Args[0]) { + os.Args[0] = sn + } + + // paths were created we're running as child. + return nil + } + + smallHash := fmt.Sprintf("elastic-agent-%s", smallHash(release.Commit())) + commitFilepath := filepath.Join(paths.Config(), commitFile) + if content, err := ioutil.ReadFile(commitFilepath); err == nil { + smallHash = hashedDirName(content) + } + + // rename itself + origExecPath, err := os.Executable() + if err != nil { + return err + } + + if err := os.Rename(origExecPath, origExecPath+".bak"); err != nil { + return err + } + + // create symlink to elastic-agent-{hash} + reexecPath := filepath.Join(paths.Data(), smallHash, filepath.Base(origExecPath)) + if err := os.Symlink(reexecPath, origExecPath); err != nil { + return err + } + + // generate paths + if err := generatePaths(filepath.Dir(reexecPath), origExecPath); err != nil { + return err + } + + paths.UpdatePaths() + + // reexec if running run + if cmd.Use == "run" { + pathConfigFile := flags.Config() + rawConfig, err := config.LoadYAML(pathConfigFile) + if err != nil { + return errors.New(err, + fmt.Sprintf("could not read configuration file %s", pathConfigFile), + errors.TypeFilesystem, + errors.M(errors.MetaKeyPath, pathConfigFile)) + } + + cfg, err := configuration.NewFromConfig(rawConfig) + if err != nil { + return errors.New(err, + fmt.Sprintf("could not parse configuration file %s", pathConfigFile), + errors.TypeFilesystem, + errors.M(errors.MetaKeyPath, pathConfigFile)) + } + + logger, err := logger.NewFromConfig("", cfg.Settings.LoggingConfig) + if err != nil { + return err + } + + rexLogger := logger.Named("reexec") + rm := reexec.NewManager(rexLogger, reexecPath) + + argsOverrides := []string{ + "--path.data", paths.Data(), + "--path.home", filepath.Dir(reexecPath), + "--path.config", paths.Config(), + } + rm.ReExec(argsOverrides...) + + // trigger reexec + rm.ShutdownComplete() + + // return without running Run method + os.Exit(0) + } + + return nil + } +} diff --git a/x-pack/elastic-agent/pkg/agent/cmd/common.go b/x-pack/elastic-agent/pkg/agent/cmd/common.go index f9b5cc9b003..d5c195566bd 100644 --- a/x-pack/elastic-agent/pkg/agent/cmd/common.go +++ b/x-pack/elastic-agent/pkg/agent/cmd/common.go @@ -6,10 +6,15 @@ package cmd import ( "flag" + "fmt" + "io/ioutil" "os" "path/filepath" + "runtime" + "strings" "github.com/spf13/cobra" + "gopkg.in/yaml.v2" // import logp flags _ "github.com/elastic/beats/v7/libbeat/logp/configure" @@ -19,7 +24,11 @@ import ( "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/cli" ) -const defaultConfig = "elastic-agent.yml" +const ( + defaultConfig = "elastic-agent.yml" + hashLen = 6 + commitFile = ".elastic-agent.active.commit" +) type globalFlags struct { PathConfigFile string @@ -71,7 +80,58 @@ func NewCommandWithArgs(args []string, streams *cli.IOStreams) *cobra.Command { if reexec != nil { cmd.AddCommand(reexec) } + cmd.PersistentPreRunE = preRunCheck(flags) cmd.Run = run.Run return cmd } + +func hashedDirName(filecontent []byte) string { + s := strings.TrimSpace(string(filecontent)) + if len(s) == 0 { + return "elastic-agent" + } + + s = smallHash(s) + + return fmt.Sprintf("elastic-agent-%s", s) +} + +func smallHash(hash string) string { + if len(hash) > hashLen { + hash = hash[:hashLen] + } + + return hash +} + +func generatePaths(dir, origExec string) error { + pathsCfg := map[string]interface{}{ + "path.data": paths.Data(), + "path.home": dir, + "path.config": paths.Config(), + "path.service_name": origExec, + } + + pathsCfgPath := filepath.Join(paths.Data(), "paths.yml") + pathsContent, err := yaml.Marshal(pathsCfg) + if err != nil { + return err + } + + if err := ioutil.WriteFile(pathsCfgPath, pathsContent, 0740); err != nil { + return err + } + + if runtime.GOOS == "windows" { + // due to two binaries we need to do a path dance + // as versioned binary will look for path inside it's own directory + versionedPath := filepath.Join(dir, "data", "paths.yml") + if err := os.MkdirAll(filepath.Dir(versionedPath), 0700); err != nil { + return err + } + return os.Symlink(pathsCfgPath, versionedPath) + } + + return nil +} diff --git a/x-pack/elastic-agent/pkg/agent/cmd/run.go b/x-pack/elastic-agent/pkg/agent/cmd/run.go index f502ef9cf49..c9d047c88ac 100644 --- a/x-pack/elastic-agent/pkg/agent/cmd/run.go +++ b/x-pack/elastic-agent/pkg/agent/cmd/run.go @@ -39,7 +39,28 @@ func newRunCommandWithArgs(flags *globalFlags, _ []string, streams *cli.IOStream } } -func run(flags *globalFlags, streams *cli.IOStreams) error { +func run(flags *globalFlags, streams *cli.IOStreams) error { // Windows: Mark service as stopped. + // After this is run, the service is considered by the OS to be stopped. + // This must be the first deferred cleanup task (last to execute). + defer service.NotifyTermination() + + locker := application.NewAppLocker(paths.Data()) + if err := locker.TryLock(); err != nil { + return err + } + defer locker.Unlock() + + service.BeforeRun() + defer service.Cleanup() + + // register as a service + stop := make(chan bool) + _, cancel := context.WithCancel(context.Background()) + var stopBeat = func() { + close(stop) + } + service.HandleSignals(stopBeat, cancel) + pathConfigFile := flags.Config() rawConfig, err := config.LoadYAML(pathConfigFile) if err != nil { @@ -62,20 +83,6 @@ func run(flags *globalFlags, streams *cli.IOStreams) error { return err } - // Windows: Mark service as stopped. - // After this is run, the service is considered by the OS to be stopped. - // This must be the first deferred cleanup task (last to execute). - defer service.NotifyTermination() - - locker := application.NewAppLocker(paths.Data()) - if err := locker.TryLock(); err != nil { - return err - } - defer locker.Unlock() - - service.BeforeRun() - defer service.Cleanup() - execPath, err := os.Executable() if err != nil { return err @@ -99,14 +106,6 @@ func run(flags *globalFlags, streams *cli.IOStreams) error { return err } - // register as a service - stop := make(chan bool) - _, cancel := context.WithCancel(context.Background()) - var stopBeat = func() { - close(stop) - } - service.HandleSignals(stopBeat, cancel) - // listen for signals signals := make(chan os.Signal, 1) signal.Notify(signals, syscall.SIGINT, syscall.SIGKILL, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGHUP) diff --git a/x-pack/elastic-agent/pkg/agent/operation/monitoring.go b/x-pack/elastic-agent/pkg/agent/operation/monitoring.go index cd9d3d95a2c..fe33de852d1 100644 --- a/x-pack/elastic-agent/pkg/agent/operation/monitoring.go +++ b/x-pack/elastic-agent/pkg/agent/operation/monitoring.go @@ -184,7 +184,7 @@ func (o *Operator) getMonitoringFilebeatConfig(output interface{}) (map[string]i "message_key": "message", }, "paths": []string{ - filepath.Join(paths.Data(), "logs", "elastic-agent-json.log"), + filepath.Join(paths.Home(), "logs", "elastic-agent-json.log"), }, "index": "logs-elastic.agent-default", "processors": []map[string]interface{}{ diff --git a/x-pack/elastic-agent/pkg/artifact/config.go b/x-pack/elastic-agent/pkg/artifact/config.go index a8a09de8e48..6faa9861710 100644 --- a/x-pack/elastic-agent/pkg/artifact/config.go +++ b/x-pack/elastic-agent/pkg/artifact/config.go @@ -47,13 +47,14 @@ type Config struct { // DefaultConfig creates a config with pre-set default values. func DefaultConfig() *Config { + homePath := paths.Home() dataPath := paths.Data() return &Config{ SourceURI: "https://artifacts.elastic.co/downloads/", - TargetDirectory: filepath.Join(dataPath, "downloads"), + TargetDirectory: filepath.Join(homePath, "downloads"), Timeout: 30 * time.Second, PgpFile: filepath.Join(dataPath, "elastic.pgp"), - InstallPath: filepath.Join(dataPath, "install"), + InstallPath: filepath.Join(homePath, "install"), } } diff --git a/x-pack/elastic-agent/pkg/artifact/download/fs/downloader.go b/x-pack/elastic-agent/pkg/artifact/download/fs/downloader.go index df289ae03ad..04f4c667e02 100644 --- a/x-pack/elastic-agent/pkg/artifact/download/fs/downloader.go +++ b/x-pack/elastic-agent/pkg/artifact/download/fs/downloader.go @@ -11,6 +11,7 @@ import ( "os" "path/filepath" + "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/application/paths" "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/errors" "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/artifact" ) @@ -19,10 +20,6 @@ const ( packagePermissions = 0660 ) -var ( - defaultDropSubdir = filepath.Join("data", "downloads") -) - // Downloader is a downloader able to fetch artifacts from elastic.co web page. type Downloader struct { dropPath string @@ -117,13 +114,13 @@ func (e *Downloader) downloadFile(filename, fullPath string) (string, error) { func getDropPath(cfg *artifact.Config) string { // if drop path is not provided fallback to beats subfolder if cfg == nil || cfg.DropPath == "" { - return defaultDropSubdir + return filepath.Join(paths.Home(), "downloads") } // if droppath does not exist fallback to beats subfolder stat, err := os.Stat(cfg.DropPath) if err != nil || !stat.IsDir() { - return defaultDropSubdir + return filepath.Join(paths.Home(), "downloads") } return cfg.DropPath diff --git a/x-pack/elastic-agent/pkg/artifact/download/fs/verifier.go b/x-pack/elastic-agent/pkg/artifact/download/fs/verifier.go index 942a412efdf..20bff381a39 100644 --- a/x-pack/elastic-agent/pkg/artifact/download/fs/verifier.go +++ b/x-pack/elastic-agent/pkg/artifact/download/fs/verifier.go @@ -18,6 +18,7 @@ import ( "golang.org/x/crypto/openpgp" + "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/application/paths" "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/errors" "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/artifact" ) @@ -144,7 +145,7 @@ func (v *Verifier) verifyAsc(filename, fullPath string) (bool, error) { func (v *Verifier) getPublicAsc(filename string) ([]byte, error) { ascFile := fmt.Sprintf("%s%s", filename, ascSuffix) - fullPath := filepath.Join(defaultDropSubdir, ascFile) + fullPath := filepath.Join(paths.Home(), "downloads", ascFile) b, err := ioutil.ReadFile(fullPath) if err != nil { diff --git a/x-pack/elastic-agent/pkg/core/logger/logger.go b/x-pack/elastic-agent/pkg/core/logger/logger.go index 0a73f36f08f..a2886ccf28e 100644 --- a/x-pack/elastic-agent/pkg/core/logger/logger.go +++ b/x-pack/elastic-agent/pkg/core/logger/logger.go @@ -100,7 +100,7 @@ func makeInternalFileOutput() (zapcore.Core, error) { // defaultCfg is used to set the defaults for the file rotation of the internal logging // these settings cannot be changed by a user configuration defaultCfg := logp.DefaultConfig(logp.DefaultEnvironment) - filename := filepath.Join(paths.Data(), "logs", fmt.Sprintf("%s-json.log", agentName)) + filename := filepath.Join(paths.Home(), "logs", fmt.Sprintf("%s-json.log", agentName)) rotator, err := file.NewFileRotator(filename, file.MaxSizeBytes(defaultCfg.Files.MaxSize), diff --git a/x-pack/elastic-agent/pkg/core/monitoring/beats/monitoring.go b/x-pack/elastic-agent/pkg/core/monitoring/beats/monitoring.go index d38f7d5843c..f75108425a0 100644 --- a/x-pack/elastic-agent/pkg/core/monitoring/beats/monitoring.go +++ b/x-pack/elastic-agent/pkg/core/monitoring/beats/monitoring.go @@ -32,8 +32,8 @@ func getMonitoringEndpoint(program, operatingSystem, pipelineID string) string { func getLoggingFile(program, operatingSystem, installPath, pipelineID string) string { if operatingSystem == "windows" { - return fmt.Sprintf(logFileFormatWin, paths.Data(), pipelineID, program) + return fmt.Sprintf(logFileFormatWin, paths.Home(), pipelineID, program) } - return fmt.Sprintf(logFileFormat, paths.Data(), pipelineID, program) + return fmt.Sprintf(logFileFormat, paths.Home(), pipelineID, program) } diff --git a/x-pack/elastic-agent/pkg/core/plugin/process/start.go b/x-pack/elastic-agent/pkg/core/plugin/process/start.go index 3b675417970..c5f1ffb3842 100644 --- a/x-pack/elastic-agent/pkg/core/plugin/process/start.go +++ b/x-pack/elastic-agent/pkg/core/plugin/process/start.go @@ -152,6 +152,6 @@ func injectLogLevel(logLevel string, args []string) []string { } func injectDataPath(args []string, pipelineID, id string) []string { - dataPath := filepath.Join(paths.Data(), "run", pipelineID, id) + dataPath := filepath.Join(paths.Home(), "run", pipelineID, id) return append(args, "-E", "path.data="+dataPath) } diff --git a/x-pack/heartbeat/magefile.go b/x-pack/heartbeat/magefile.go index 85aeae0c98f..83f3593c117 100644 --- a/x-pack/heartbeat/magefile.go +++ b/x-pack/heartbeat/magefile.go @@ -8,6 +8,7 @@ package main import ( "fmt" + "os" "time" "github.com/magefile/mage/mg" @@ -48,7 +49,12 @@ func Package() { start := time.Now() defer func() { fmt.Println("package ran for", time.Since(start)) }() - devtools.UseElasticBeatXPackPackaging() + if v, found := os.LookupEnv("AGENT_PACKAGING"); found && v != "" { + devtools.UseElasticBeatXPackReducedPackaging() + } else { + devtools.UseElasticBeatXPackPackaging() + } + devtools.PackageKibanaDashboardsFromBuildDir() heartbeat.CustomizePackaging()