Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions dev-tools/packaging/packages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ shared:
'data/{{.BeatName}}-{{ commit_short }}/components/agentbeat.spec.yml':
source: '{{.AgentDropPath}}/{{.GOOS}}-{{.AgentArchName}}.tar.gz/agentbeat.spec.yml'
expand_spec: true

- &agent_docker_edot_wolfi_spec
<<: *agent_docker_edot_spec
docker_variant: 'elastic-otel-collector-wolfi'
Expand Down Expand Up @@ -370,7 +370,7 @@ shared:
'data/{{.BeatName}}-{{ commit_short }}/components/pf-host-agent.spec.yml':
source: '{{.AgentDropPath}}/{{.GOOS}}-{{.AgentArchName}}.tar.gz/pf-host-agent.spec.yml'
expand_spec: true

- &agent_docker_slim_wolfi_spec
<<: *agent_docker_slim_spec
docker_variant: 'slim-wolfi'
Expand Down Expand Up @@ -922,7 +922,7 @@ specs:
<<: *elastic_license_for_binaries
files:
'{{.BeatName}}{{.BinaryExt}}':
source: ./build/golang-crossbuild/{{.BeatName}}-{{.GOOS}}-{{.Platform.Arch}}{{.BinaryExt}}
source: ./build/windows-archive-root-binary/elastic-agent-archive-root.exe
'package.version':
content: >
{{ agent_package_version }}
Expand Down
54 changes: 54 additions & 0 deletions magefile.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,54 @@ func (Build) GenerateConfig() error {
return sh.Copy(filepath.Join(buildDir, configFile), filepath.Join(metaDir, configFile))
}

// WindowsArchiveRootBinary compiles a binary to be placed at the root of the windows elastic-agent archive. This binary
// is a thin proxy to the actual elastic-agent binary that resides in the data/elastic-agent-{commit-short-sha}
// directory of the archive.
func (Build) WindowsArchiveRootBinary() error {
fmt.Println("--- Compiling root binary for windows archive")
hashShort, err := devtools.CommitHashShort()
if err != nil {
return fmt.Errorf("error getting commit hash: %w", err)
}

outputName := "elastic-agent-archive-root"
if runtime.GOOS != "windows" {
// add the .exe extension on non-windows platforms
outputName += ".exe"
}

args := devtools.BuildArgs{
Name: outputName,
OutputDir: filepath.Join(buildDir, "windows-archive-root-binary"),
InputFiles: []string{"wrapper/windows/archive-proxy/main.go"},
CGO: false,
WinMetadata: true,
ExtraFlags: []string{
"-buildmode", "pie", // windows versions inside the support matrix do support position independent code
"-trimpath", // Remove all file system paths from the compiled executable, to improve build reproducibility
},
Vars: map[string]string{
"main.CommitSHA": hashShort,
},
Env: map[string]string{
"GOOS": "windows",
"GOARCH": "amd64",
},
LDFlags: []string{
"-s", // Strip all debug symbols from binary (does not affect Go stack traces).
},
}

if devtools.FIPSBuild {
// there is no actual FIPS relevance for this particular binary
// but better safe than sorry
args.ExtraFlags = append(args.ExtraFlags, "-tags=requirefips")
args.CGO = true
}

return devtools.Build(args)
}

// GolangCrossBuildOSS build the Beat binary inside of the golang-builder.
// Do not use directly, use crossBuild instead.
func GolangCrossBuildOSS() error {
Expand Down Expand Up @@ -1022,6 +1070,12 @@ func packageAgent(ctx context.Context, platforms []string, dependenciesVersion s
log.Println("--- Running post packaging ")
mg.Deps(Update)
mg.Deps(agentBinaryTarget, CrossBuildGoDaemon)

// compile the elastic-agent.exe proxy binary for the windows archive
if slices.Contains(platforms, "windows/amd64") {
mg.Deps(Build.WindowsArchiveRootBinary)
}

mg.SerialDeps(devtools.Package, TestPackages)
return nil
}
Expand Down
9 changes: 9 additions & 0 deletions wrapper/windows/archive-proxy/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module github.com/elastic/elastic-agent/wrapper/windows/archive-proxy

go 1.24.1

require github.com/elastic/elastic-agent v0.0.0

require golang.org/x/sys v0.31.0 // indirect

replace github.com/elastic/elastic-agent => ../../../
1 change: 1 addition & 0 deletions wrapper/windows/archive-proxy/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
93 changes: 93 additions & 0 deletions wrapper/windows/archive-proxy/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
// or more contributor license agreements. Licensed under the Elastic License 2.0;
// you may not use this file except in compliance with the Elastic License 2.0.

package main

import (
"errors"
"fmt"
"log"
"os"
"os/exec"
"path/filepath"

"github.com/elastic/elastic-agent/pkg/core/process"
)

// CommitSHA is set by the linker at build time
var CommitSHA string

func main() {
log.SetFlags(0)
if CommitSHA == "" {
// this should never happen
log.Fatal("No commit SHA provided\n")
}

exePath, err := os.Executable()
if err != nil {
log.Fatalf("Error getting executable path: %v\n", err)
}

exeAbsPath, err := filepath.Abs(exePath)
if err != nil {
log.Fatalf("Error getting executable absolute path: %v\n", err)
}

// Fabricate the elastic-agent.exe path that resides inside the data/elastic-agent-{commit-short-sha} directory
exeTopPath := filepath.Dir(exeAbsPath)
nestedAgentBinaryPath := filepath.Join(exeTopPath, "data", fmt.Sprintf("elastic-agent-%s", CommitSHA), "elastic-agent.exe")

// Create the arguments
var args []string
if len(os.Args) > 1 {
args = os.Args[1:]
}

g, err := process.CreateJobObject()
if err != nil {
log.Fatalf("Unable to create job object: %v\n", err)
}
defer func() {
_ = g.Close()
}()

// Create the command
command := exec.Command(nestedAgentBinaryPath, args...)

// Forward stdout, stderr, stdin
command.Stdout = os.Stdout
command.Stderr = os.Stderr
command.Stdin = os.Stdin

// Pass the environment
command.Env = os.Environ()

// Run the command
err = command.Start()
if err != nil {
log.Fatalf("Error running command: %v\n", err)
}

// Add the process to the job object
if err := g.Assign(command.Process); err != nil {
log.Fatalf("Error adding job object: %v\n", err)
}

err = command.Wait()
var exitError *exec.ExitError
switch {
case errors.As(err, &exitError):
exitCode := exitError.ExitCode()
if exitCode == 0 {
// Exit with non-zero exit code since we did get an error
os.Exit(1)
}
// Exit with the same exit code
os.Exit(exitCode)
case err != nil:
// Exit with a non-zero exit code
log.Fatalf("Command failed: %v\n", err)
}
}