Skip to content

Commit 6b4b0dc

Browse files
[packaging] proxy binary to be for the root dir of windows archive (#7601)
* feat: implement a proxy binary to be placed in the root of windows archive and invoke the nested elastic-agent binary * fix: remove redundant returns in the code * fix: reword error message when we cannot stat inner elastic-agent binary * fix: use slices.Contains to check if we are building for windows/amd64 * fix: add comment to capture that CommitSHA is set at build time * fix: rename hack folder to wrapper * fix: reside typo * fix: reword error message when we cannot stat inner elastic-agent binary * ci: automate go version updates for wrapper/windows/archive-proxy/go.mod * fix: switch logging to fmt and also log to windows event logger * Revert "ci: automate go version updates for wrapper/windows/archive-proxy/go.mod" This reverts commit c9a698b. * fix: initialise windows event log only if we are admin * fix: remove os.Stat call and rely on command.Start() to raise an error if binary is missing * fix: remove custom logger
1 parent 03b3b14 commit 6b4b0dc

File tree

5 files changed

+160
-3
lines changed

5 files changed

+160
-3
lines changed

dev-tools/packaging/packages.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ shared:
333333
'data/{{.BeatName}}-{{ commit_short }}/components/agentbeat.spec.yml':
334334
source: '{{.AgentDropPath}}/{{.GOOS}}-{{.AgentArchName}}.tar.gz/agentbeat.spec.yml'
335335
expand_spec: true
336-
336+
337337
- &agent_docker_edot_wolfi_spec
338338
<<: *agent_docker_edot_spec
339339
docker_variant: 'elastic-otel-collector-wolfi'
@@ -370,7 +370,7 @@ shared:
370370
'data/{{.BeatName}}-{{ commit_short }}/components/pf-host-agent.spec.yml':
371371
source: '{{.AgentDropPath}}/{{.GOOS}}-{{.AgentArchName}}.tar.gz/pf-host-agent.spec.yml'
372372
expand_spec: true
373-
373+
374374
- &agent_docker_slim_wolfi_spec
375375
<<: *agent_docker_slim_spec
376376
docker_variant: 'slim-wolfi'
@@ -922,7 +922,7 @@ specs:
922922
<<: *elastic_license_for_binaries
923923
files:
924924
'{{.BeatName}}{{.BinaryExt}}':
925-
source: ./build/golang-crossbuild/{{.BeatName}}-{{.GOOS}}-{{.Platform.Arch}}{{.BinaryExt}}
925+
source: ./build/windows-archive-root-binary/elastic-agent-archive-root.exe
926926
'package.version':
927927
content: >
928928
{{ agent_package_version }}

magefile.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,54 @@ func (Build) GenerateConfig() error {
295295
return sh.Copy(filepath.Join(buildDir, configFile), filepath.Join(metaDir, configFile))
296296
}
297297

298+
// WindowsArchiveRootBinary compiles a binary to be placed at the root of the windows elastic-agent archive. This binary
299+
// is a thin proxy to the actual elastic-agent binary that resides in the data/elastic-agent-{commit-short-sha}
300+
// directory of the archive.
301+
func (Build) WindowsArchiveRootBinary() error {
302+
fmt.Println("--- Compiling root binary for windows archive")
303+
hashShort, err := devtools.CommitHashShort()
304+
if err != nil {
305+
return fmt.Errorf("error getting commit hash: %w", err)
306+
}
307+
308+
outputName := "elastic-agent-archive-root"
309+
if runtime.GOOS != "windows" {
310+
// add the .exe extension on non-windows platforms
311+
outputName += ".exe"
312+
}
313+
314+
args := devtools.BuildArgs{
315+
Name: outputName,
316+
OutputDir: filepath.Join(buildDir, "windows-archive-root-binary"),
317+
InputFiles: []string{"wrapper/windows/archive-proxy/main.go"},
318+
CGO: false,
319+
WinMetadata: true,
320+
ExtraFlags: []string{
321+
"-buildmode", "pie", // windows versions inside the support matrix do support position independent code
322+
"-trimpath", // Remove all file system paths from the compiled executable, to improve build reproducibility
323+
},
324+
Vars: map[string]string{
325+
"main.CommitSHA": hashShort,
326+
},
327+
Env: map[string]string{
328+
"GOOS": "windows",
329+
"GOARCH": "amd64",
330+
},
331+
LDFlags: []string{
332+
"-s", // Strip all debug symbols from binary (does not affect Go stack traces).
333+
},
334+
}
335+
336+
if devtools.FIPSBuild {
337+
// there is no actual FIPS relevance for this particular binary
338+
// but better safe than sorry
339+
args.ExtraFlags = append(args.ExtraFlags, "-tags=requirefips")
340+
args.CGO = true
341+
}
342+
343+
return devtools.Build(args)
344+
}
345+
298346
// GolangCrossBuildOSS build the Beat binary inside of the golang-builder.
299347
// Do not use directly, use crossBuild instead.
300348
func GolangCrossBuildOSS() error {
@@ -1023,6 +1071,12 @@ func packageAgent(ctx context.Context, platforms []string, dependenciesVersion s
10231071
log.Println("--- Running post packaging ")
10241072
mg.Deps(Update)
10251073
mg.Deps(agentBinaryTarget, CrossBuildGoDaemon)
1074+
1075+
// compile the elastic-agent.exe proxy binary for the windows archive
1076+
if slices.Contains(platforms, "windows/amd64") {
1077+
mg.Deps(Build.WindowsArchiveRootBinary)
1078+
}
1079+
10261080
mg.SerialDeps(devtools.Package, TestPackages)
10271081
return nil
10281082
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module github.com/elastic/elastic-agent/wrapper/windows/archive-proxy
2+
3+
go 1.24.1
4+
5+
require github.com/elastic/elastic-agent v0.0.0
6+
7+
require golang.org/x/sys v0.31.0 // indirect
8+
9+
replace github.com/elastic/elastic-agent => ../../../
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
2+
// or more contributor license agreements. Licensed under the Elastic License 2.0;
3+
// you may not use this file except in compliance with the Elastic License 2.0.
4+
5+
package main
6+
7+
import (
8+
"errors"
9+
"fmt"
10+
"log"
11+
"os"
12+
"os/exec"
13+
"path/filepath"
14+
15+
"github.com/elastic/elastic-agent/pkg/core/process"
16+
)
17+
18+
// CommitSHA is set by the linker at build time
19+
var CommitSHA string
20+
21+
func main() {
22+
log.SetFlags(0)
23+
if CommitSHA == "" {
24+
// this should never happen
25+
log.Fatal("No commit SHA provided\n")
26+
}
27+
28+
exePath, err := os.Executable()
29+
if err != nil {
30+
log.Fatalf("Error getting executable path: %v\n", err)
31+
}
32+
33+
exeAbsPath, err := filepath.Abs(exePath)
34+
if err != nil {
35+
log.Fatalf("Error getting executable absolute path: %v\n", err)
36+
}
37+
38+
// Fabricate the elastic-agent.exe path that resides inside the data/elastic-agent-{commit-short-sha} directory
39+
exeTopPath := filepath.Dir(exeAbsPath)
40+
nestedAgentBinaryPath := filepath.Join(exeTopPath, "data", fmt.Sprintf("elastic-agent-%s", CommitSHA), "elastic-agent.exe")
41+
42+
// Create the arguments
43+
var args []string
44+
if len(os.Args) > 1 {
45+
args = os.Args[1:]
46+
}
47+
48+
g, err := process.CreateJobObject()
49+
if err != nil {
50+
log.Fatalf("Unable to create job object: %v\n", err)
51+
}
52+
defer func() {
53+
_ = g.Close()
54+
}()
55+
56+
// Create the command
57+
command := exec.Command(nestedAgentBinaryPath, args...)
58+
59+
// Forward stdout, stderr, stdin
60+
command.Stdout = os.Stdout
61+
command.Stderr = os.Stderr
62+
command.Stdin = os.Stdin
63+
64+
// Pass the environment
65+
command.Env = os.Environ()
66+
67+
// Run the command
68+
err = command.Start()
69+
if err != nil {
70+
log.Fatalf("Error running command: %v\n", err)
71+
}
72+
73+
// Add the process to the job object
74+
if err := g.Assign(command.Process); err != nil {
75+
log.Fatalf("Error adding job object: %v\n", err)
76+
}
77+
78+
err = command.Wait()
79+
var exitError *exec.ExitError
80+
switch {
81+
case errors.As(err, &exitError):
82+
exitCode := exitError.ExitCode()
83+
if exitCode == 0 {
84+
// Exit with non-zero exit code since we did get an error
85+
os.Exit(1)
86+
}
87+
// Exit with the same exit code
88+
os.Exit(exitCode)
89+
case err != nil:
90+
// Exit with a non-zero exit code
91+
log.Fatalf("Command failed: %v\n", err)
92+
}
93+
}

0 commit comments

Comments
 (0)