From 159b7b69059072140e56cb4f0b747e4171f259a8 Mon Sep 17 00:00:00 2001 From: Panos Koutsovasilis Date: Fri, 28 Mar 2025 05:02:39 +0200 Subject: [PATCH 01/14] feat: implement a proxy binary to be placed in the root of windows archive and invoke the nested elastic-agent binary --- dev-tools/packaging/packages.yml | 6 +- hack/windows/archive-proxy/go.mod | 9 +++ hack/windows/archive-proxy/go.sum | 1 + hack/windows/archive-proxy/main.go | 96 ++++++++++++++++++++++++++++++ magefile.go | 57 ++++++++++++++++++ 5 files changed, 166 insertions(+), 3 deletions(-) create mode 100644 hack/windows/archive-proxy/go.mod create mode 100644 hack/windows/archive-proxy/go.sum create mode 100644 hack/windows/archive-proxy/main.go diff --git a/dev-tools/packaging/packages.yml b/dev-tools/packaging/packages.yml index 5254991306e..688342fe42f 100644 --- a/dev-tools/packaging/packages.yml +++ b/dev-tools/packaging/packages.yml @@ -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' @@ -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' @@ -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 }} diff --git a/hack/windows/archive-proxy/go.mod b/hack/windows/archive-proxy/go.mod new file mode 100644 index 00000000000..1d845f35f49 --- /dev/null +++ b/hack/windows/archive-proxy/go.mod @@ -0,0 +1,9 @@ +module github.com/elastic/elastic-agent/hack/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 => ../../../ diff --git a/hack/windows/archive-proxy/go.sum b/hack/windows/archive-proxy/go.sum new file mode 100644 index 00000000000..802d06db8a3 --- /dev/null +++ b/hack/windows/archive-proxy/go.sum @@ -0,0 +1 @@ +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= diff --git a/hack/windows/archive-proxy/main.go b/hack/windows/archive-proxy/main.go new file mode 100644 index 00000000000..e604421a004 --- /dev/null +++ b/hack/windows/archive-proxy/main.go @@ -0,0 +1,96 @@ +// 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" +) + +var CommitSHA string + +func main() { + if CommitSHA == "" { + // this should never happen + log.Fatal("No commit SHA provided") + } + + exePath, err := os.Executable() + if err != nil { + log.Fatalf("Error getting executable path: %v\n", err) + return + } + + exeAbsPath, err := filepath.Abs(exePath) + if err != nil { + log.Fatalf("Error getting executable absolute path: %v\n", err) + return + } + + // Fabricate the elastic-agent.exe path that reside 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") + if _, err := os.Stat(nestedAgentBinaryPath); err != nil { + log.Fatalf("Unable to stat nested agent binary %q: %v\n", nestedAgentBinaryPath, err) + } + + // 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) + } +} diff --git a/magefile.go b/magefile.go index ef3910f8129..4dc21822e54 100644 --- a/magefile.go +++ b/magefile.go @@ -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{"hack/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 { @@ -1022,6 +1070,15 @@ 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 + for _, platform := range platforms { + if platform == "windows/amd64" { + mg.Deps(Build.WindowsArchiveRootBinary) + break + } + } + mg.SerialDeps(devtools.Package, TestPackages) return nil } From 521e771eeeb0991f5d4ca26a43c9213f7cf0e726 Mon Sep 17 00:00:00 2001 From: Panos Koutsovasilis Date: Fri, 28 Mar 2025 15:19:32 +0200 Subject: [PATCH 02/14] fix: remove redundant returns in the code --- hack/windows/archive-proxy/main.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/hack/windows/archive-proxy/main.go b/hack/windows/archive-proxy/main.go index e604421a004..9d2726a8154 100644 --- a/hack/windows/archive-proxy/main.go +++ b/hack/windows/archive-proxy/main.go @@ -26,13 +26,11 @@ func main() { exePath, err := os.Executable() if err != nil { log.Fatalf("Error getting executable path: %v\n", err) - return } exeAbsPath, err := filepath.Abs(exePath) if err != nil { log.Fatalf("Error getting executable absolute path: %v\n", err) - return } // Fabricate the elastic-agent.exe path that reside inside the data/elastic-agent-{commit-short-sha} directory From 6f5df45c300ccb81f93b601b76d47e56d4a78654 Mon Sep 17 00:00:00 2001 From: Panos Koutsovasilis Date: Fri, 28 Mar 2025 15:20:22 +0200 Subject: [PATCH 03/14] fix: reword error message when we cannot stat inner elastic-agent binary --- hack/windows/archive-proxy/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hack/windows/archive-proxy/main.go b/hack/windows/archive-proxy/main.go index 9d2726a8154..264e7b23f53 100644 --- a/hack/windows/archive-proxy/main.go +++ b/hack/windows/archive-proxy/main.go @@ -37,7 +37,7 @@ func main() { exeTopPath := filepath.Dir(exeAbsPath) nestedAgentBinaryPath := filepath.Join(exeTopPath, "data", fmt.Sprintf("elastic-agent-%s", CommitSHA), "elastic-agent.exe") if _, err := os.Stat(nestedAgentBinaryPath); err != nil { - log.Fatalf("Unable to stat nested agent binary %q: %v\n", nestedAgentBinaryPath, err) + log.Fatalf("Unable to stat inner agent binary at %q: %v\n", nestedAgentBinaryPath, err) } // Create the arguments From fe889d436efbbcbaf43820b3a2711c9acf09919e Mon Sep 17 00:00:00 2001 From: Panos Koutsovasilis Date: Fri, 28 Mar 2025 15:24:36 +0200 Subject: [PATCH 04/14] fix: use slices.Contains to check if we are building for windows/amd64 --- magefile.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/magefile.go b/magefile.go index 4dc21822e54..67d6ad2bfc3 100644 --- a/magefile.go +++ b/magefile.go @@ -1072,11 +1072,8 @@ func packageAgent(ctx context.Context, platforms []string, dependenciesVersion s mg.Deps(agentBinaryTarget, CrossBuildGoDaemon) // compile the elastic-agent.exe proxy binary for the windows archive - for _, platform := range platforms { - if platform == "windows/amd64" { - mg.Deps(Build.WindowsArchiveRootBinary) - break - } + if slices.Contains(platforms, "windows/amd64") { + mg.Deps(Build.WindowsArchiveRootBinary) } mg.SerialDeps(devtools.Package, TestPackages) From bc4c38c8b1f51e1d7e79d16008e8ea6497daa2da Mon Sep 17 00:00:00 2001 From: Panos Koutsovasilis Date: Fri, 28 Mar 2025 15:47:23 +0200 Subject: [PATCH 05/14] fix: add comment to capture that CommitSHA is set at build time --- hack/windows/archive-proxy/main.go | 1 + 1 file changed, 1 insertion(+) diff --git a/hack/windows/archive-proxy/main.go b/hack/windows/archive-proxy/main.go index 264e7b23f53..e5ccc51696f 100644 --- a/hack/windows/archive-proxy/main.go +++ b/hack/windows/archive-proxy/main.go @@ -15,6 +15,7 @@ import ( "github.com/elastic/elastic-agent/pkg/core/process" ) +// CommitSHA is set by the linker at build time var CommitSHA string func main() { From 40c08a7aa7eed31cb885f76bec5a00e832f5ce61 Mon Sep 17 00:00:00 2001 From: Panos Koutsovasilis Date: Fri, 28 Mar 2025 16:16:08 +0200 Subject: [PATCH 06/14] fix: rename hack folder to wrapper --- magefile.go | 2 +- {hack => wrapper}/windows/archive-proxy/go.mod | 2 +- {hack => wrapper}/windows/archive-proxy/go.sum | 0 {hack => wrapper}/windows/archive-proxy/main.go | 0 4 files changed, 2 insertions(+), 2 deletions(-) rename {hack => wrapper}/windows/archive-proxy/go.mod (69%) rename {hack => wrapper}/windows/archive-proxy/go.sum (100%) rename {hack => wrapper}/windows/archive-proxy/main.go (100%) diff --git a/magefile.go b/magefile.go index 67d6ad2bfc3..7937b81198d 100644 --- a/magefile.go +++ b/magefile.go @@ -313,7 +313,7 @@ func (Build) WindowsArchiveRootBinary() error { args := devtools.BuildArgs{ Name: outputName, OutputDir: filepath.Join(buildDir, "windows-archive-root-binary"), - InputFiles: []string{"hack/windows/archive-proxy/main.go"}, + InputFiles: []string{"wrapper/windows/archive-proxy/main.go"}, CGO: false, WinMetadata: true, ExtraFlags: []string{ diff --git a/hack/windows/archive-proxy/go.mod b/wrapper/windows/archive-proxy/go.mod similarity index 69% rename from hack/windows/archive-proxy/go.mod rename to wrapper/windows/archive-proxy/go.mod index 1d845f35f49..4c5e00e5f9e 100644 --- a/hack/windows/archive-proxy/go.mod +++ b/wrapper/windows/archive-proxy/go.mod @@ -1,4 +1,4 @@ -module github.com/elastic/elastic-agent/hack/windows/archive-proxy +module github.com/elastic/elastic-agent/wrapper/windows/archive-proxy go 1.24.1 diff --git a/hack/windows/archive-proxy/go.sum b/wrapper/windows/archive-proxy/go.sum similarity index 100% rename from hack/windows/archive-proxy/go.sum rename to wrapper/windows/archive-proxy/go.sum diff --git a/hack/windows/archive-proxy/main.go b/wrapper/windows/archive-proxy/main.go similarity index 100% rename from hack/windows/archive-proxy/main.go rename to wrapper/windows/archive-proxy/main.go From 0a4702703a721290cc3a9f52e5c38fbe95400f71 Mon Sep 17 00:00:00 2001 From: Panos Koutsovasilis Date: Fri, 28 Mar 2025 16:37:58 +0200 Subject: [PATCH 07/14] fix: reside typo --- wrapper/windows/archive-proxy/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrapper/windows/archive-proxy/main.go b/wrapper/windows/archive-proxy/main.go index e5ccc51696f..f09c91e4b28 100644 --- a/wrapper/windows/archive-proxy/main.go +++ b/wrapper/windows/archive-proxy/main.go @@ -34,7 +34,7 @@ func main() { log.Fatalf("Error getting executable absolute path: %v\n", err) } - // Fabricate the elastic-agent.exe path that reside inside the data/elastic-agent-{commit-short-sha} directory + // 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") if _, err := os.Stat(nestedAgentBinaryPath); err != nil { From 316fc118304a26ff4e267a6dca316fd2890bd888 Mon Sep 17 00:00:00 2001 From: Panos Koutsovasilis Date: Fri, 28 Mar 2025 16:39:08 +0200 Subject: [PATCH 08/14] fix: reword error message when we cannot stat inner elastic-agent binary --- wrapper/windows/archive-proxy/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrapper/windows/archive-proxy/main.go b/wrapper/windows/archive-proxy/main.go index f09c91e4b28..7fc15402404 100644 --- a/wrapper/windows/archive-proxy/main.go +++ b/wrapper/windows/archive-proxy/main.go @@ -38,7 +38,7 @@ func main() { exeTopPath := filepath.Dir(exeAbsPath) nestedAgentBinaryPath := filepath.Join(exeTopPath, "data", fmt.Sprintf("elastic-agent-%s", CommitSHA), "elastic-agent.exe") if _, err := os.Stat(nestedAgentBinaryPath); err != nil { - log.Fatalf("Unable to stat inner agent binary at %q: %v\n", nestedAgentBinaryPath, err) + log.Fatalf("Unable to execute elastic-agent.exe at %q: %v\n", nestedAgentBinaryPath, err) } // Create the arguments From c9a698b0ee1a0ecef6c70cd8042085b12576fbff Mon Sep 17 00:00:00 2001 From: Panos Koutsovasilis Date: Fri, 28 Mar 2025 16:44:59 +0200 Subject: [PATCH 09/14] ci: automate go version updates for wrapper/windows/archive-proxy/go.mod --- .ci/updatecli/updatecli-bump-golang.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.ci/updatecli/updatecli-bump-golang.yml b/.ci/updatecli/updatecli-bump-golang.yml index 432d6bf0f5b..6cdb01acc87 100644 --- a/.ci/updatecli/updatecli-bump-golang.yml +++ b/.ci/updatecli/updatecli-bump-golang.yml @@ -113,6 +113,15 @@ targets: content: 'go {{ source "latestGoVersion" }}' file: go.mod matchpattern: 'go \d+.\d+.\d+' + update-wrapper-windows-archive-gomod-full-version: + name: "Update wrapper-windows-archive go.mod version" + sourceid: latestGoVersion + scmid: githubConfig + kind: file + spec: + content: 'go {{ source "latestGoVersion" }}' + file: wrapper/windows/archive-proxy/go.mod + matchpattern: 'go \d+.\d+.\d+' update-buildkite-pipeline: name: "Update .buildkite/pipeline.yml" sourceid: latestGoVersion From e7c6ed69dee872b3bcfdccb07938af7252e7120f Mon Sep 17 00:00:00 2001 From: Panos Koutsovasilis Date: Fri, 28 Mar 2025 17:24:30 +0200 Subject: [PATCH 10/14] fix: switch logging to fmt and also log to windows event logger --- wrapper/windows/archive-proxy/main.go | 56 ++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/wrapper/windows/archive-proxy/main.go b/wrapper/windows/archive-proxy/main.go index 7fc15402404..ab24bbe35b0 100644 --- a/wrapper/windows/archive-proxy/main.go +++ b/wrapper/windows/archive-proxy/main.go @@ -7,18 +7,72 @@ package main import ( "errors" "fmt" - "log" "os" "os/exec" "path/filepath" + "strings" + "golang.org/x/sys/windows/svc/eventlog" + + "github.com/elastic/elastic-agent/internal/pkg/agent/application/paths" "github.com/elastic/elastic-agent/pkg/core/process" ) // CommitSHA is set by the linker at build time var CommitSHA string +// logger prints messages to stdout and the windows event log +type logger struct { + winEventLog interface { + Error(eid uint32, msg string) error + Close() error + } +} + +// newLogger creates a new logger +func newLogger() (*logger, error) { + err := eventlog.InstallAsEventCreate(paths.ServiceName(), eventlog.Info|eventlog.Warning|eventlog.Error) + if err != nil && !strings.Contains(err.Error(), "registry key already exists") { + return nil, err + } + + eLog, err := eventlog.Open(paths.ServiceName()) + if err != nil { + return nil, err + } + + return &logger{ + winEventLog: eLog, + }, nil +} + +// Close closes the event log +func (l *logger) Close() { + _ = l.winEventLog.Close() +} + +// Fatal is equivalent to [fmt.Print] followed by a call to [os.Exit](1). +func (l *logger) Fatal(v ...any) { + msg := fmt.Sprint(v...) + _ = l.winEventLog.Error(1, msg) + os.Exit(1) +} + +// Fatalf is equivalent to [fmt.Printf] followed by a call to [os.Exit](1). +func (l *logger) Fatalf(format string, v ...any) { + msg := fmt.Sprintf(format, v...) + _ = l.winEventLog.Error(1, msg) + os.Exit(1) +} + func main() { + log, err := newLogger() + if err != nil { + fmt.Printf("Error creating logger: %v\n", err) + os.Exit(1) + } + defer log.Close() + if CommitSHA == "" { // this should never happen log.Fatal("No commit SHA provided") From b088b05454db18023079a7d9f46469a5c8d7eda8 Mon Sep 17 00:00:00 2001 From: Panos Koutsovasilis Date: Fri, 28 Mar 2025 17:28:44 +0200 Subject: [PATCH 11/14] Revert "ci: automate go version updates for wrapper/windows/archive-proxy/go.mod" This reverts commit c9a698b0ee1a0ecef6c70cd8042085b12576fbff. --- .ci/updatecli/updatecli-bump-golang.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.ci/updatecli/updatecli-bump-golang.yml b/.ci/updatecli/updatecli-bump-golang.yml index 6cdb01acc87..432d6bf0f5b 100644 --- a/.ci/updatecli/updatecli-bump-golang.yml +++ b/.ci/updatecli/updatecli-bump-golang.yml @@ -113,15 +113,6 @@ targets: content: 'go {{ source "latestGoVersion" }}' file: go.mod matchpattern: 'go \d+.\d+.\d+' - update-wrapper-windows-archive-gomod-full-version: - name: "Update wrapper-windows-archive go.mod version" - sourceid: latestGoVersion - scmid: githubConfig - kind: file - spec: - content: 'go {{ source "latestGoVersion" }}' - file: wrapper/windows/archive-proxy/go.mod - matchpattern: 'go \d+.\d+.\d+' update-buildkite-pipeline: name: "Update .buildkite/pipeline.yml" sourceid: latestGoVersion From df09d406af715e39762ab5b732ea98c730c88229 Mon Sep 17 00:00:00 2001 From: Panos Koutsovasilis Date: Fri, 28 Mar 2025 17:45:28 +0200 Subject: [PATCH 12/14] fix: initialise windows event log only if we are admin --- wrapper/windows/archive-proxy/main.go | 58 ++++++++++++++++++++------- 1 file changed, 44 insertions(+), 14 deletions(-) diff --git a/wrapper/windows/archive-proxy/main.go b/wrapper/windows/archive-proxy/main.go index ab24bbe35b0..d4c934ff49c 100644 --- a/wrapper/windows/archive-proxy/main.go +++ b/wrapper/windows/archive-proxy/main.go @@ -16,52 +16,82 @@ import ( "github.com/elastic/elastic-agent/internal/pkg/agent/application/paths" "github.com/elastic/elastic-agent/pkg/core/process" + "github.com/elastic/elastic-agent/pkg/utils" ) // CommitSHA is set by the linker at build time var CommitSHA string +// winEventLog is an interface for windows event log +type winEventLog interface { + Error(eid uint32, msg string) error + Close() error +} + // logger prints messages to stdout and the windows event log type logger struct { - winEventLog interface { - Error(eid uint32, msg string) error - Close() error - } + wel winEventLog } // newLogger creates a new logger func newLogger() (*logger, error) { - err := eventlog.InstallAsEventCreate(paths.ServiceName(), eventlog.Info|eventlog.Warning|eventlog.Error) - if err != nil && !strings.Contains(err.Error(), "registry key already exists") { - return nil, err + isAdmin, err := utils.HasRoot() + if err != nil { + isAdmin = false } - eLog, err := eventlog.Open(paths.ServiceName()) - if err != nil { - return nil, err + var wel winEventLog + if isAdmin { + src := paths.ServiceName() + + err := eventlog.InstallAsEventCreate(src, eventlog.Info|eventlog.Warning|eventlog.Error) + if err != nil && !strings.Contains(err.Error(), "registry key already exists") { + return nil, err + } + + eLog, err := eventlog.Open(src) + if err != nil { + return nil, err + } + wel = eLog } return &logger{ - winEventLog: eLog, + wel: wel, }, nil } // Close closes the event log func (l *logger) Close() { - _ = l.winEventLog.Close() + if l == nil || l.wel == nil { + return + } + _ = l.wel.Close() } // Fatal is equivalent to [fmt.Print] followed by a call to [os.Exit](1). func (l *logger) Fatal(v ...any) { + if l == nil { + return + } msg := fmt.Sprint(v...) - _ = l.winEventLog.Error(1, msg) + if l.wel != nil { + _ = l.wel.Error(1, msg) + } + fmt.Println(msg) os.Exit(1) } // Fatalf is equivalent to [fmt.Printf] followed by a call to [os.Exit](1). func (l *logger) Fatalf(format string, v ...any) { + if l == nil { + return + } msg := fmt.Sprintf(format, v...) - _ = l.winEventLog.Error(1, msg) + if l.wel != nil { + _ = l.wel.Error(1, msg) + } + fmt.Println(msg) os.Exit(1) } From 39d651a1364454038876c55f77292093f507f2d3 Mon Sep 17 00:00:00 2001 From: Panos Koutsovasilis Date: Fri, 28 Mar 2025 17:54:19 +0200 Subject: [PATCH 13/14] fix: remove os.Stat call and rely on command.Start() to raise an error if binary is missing --- wrapper/windows/archive-proxy/main.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/wrapper/windows/archive-proxy/main.go b/wrapper/windows/archive-proxy/main.go index d4c934ff49c..376082d2be6 100644 --- a/wrapper/windows/archive-proxy/main.go +++ b/wrapper/windows/archive-proxy/main.go @@ -121,9 +121,6 @@ func main() { // 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") - if _, err := os.Stat(nestedAgentBinaryPath); err != nil { - log.Fatalf("Unable to execute elastic-agent.exe at %q: %v\n", nestedAgentBinaryPath, err) - } // Create the arguments var args []string From efe5fd5c41f8a0e06bbc940a133695b66752fff3 Mon Sep 17 00:00:00 2001 From: Panos Koutsovasilis Date: Fri, 28 Mar 2025 18:48:09 +0200 Subject: [PATCH 14/14] fix: remove custom logger --- wrapper/windows/archive-proxy/main.go | 89 +-------------------------- 1 file changed, 3 insertions(+), 86 deletions(-) diff --git a/wrapper/windows/archive-proxy/main.go b/wrapper/windows/archive-proxy/main.go index 376082d2be6..dc892e04325 100644 --- a/wrapper/windows/archive-proxy/main.go +++ b/wrapper/windows/archive-proxy/main.go @@ -7,105 +7,22 @@ package main import ( "errors" "fmt" + "log" "os" "os/exec" "path/filepath" - "strings" - "golang.org/x/sys/windows/svc/eventlog" - - "github.com/elastic/elastic-agent/internal/pkg/agent/application/paths" "github.com/elastic/elastic-agent/pkg/core/process" - "github.com/elastic/elastic-agent/pkg/utils" ) // CommitSHA is set by the linker at build time var CommitSHA string -// winEventLog is an interface for windows event log -type winEventLog interface { - Error(eid uint32, msg string) error - Close() error -} - -// logger prints messages to stdout and the windows event log -type logger struct { - wel winEventLog -} - -// newLogger creates a new logger -func newLogger() (*logger, error) { - isAdmin, err := utils.HasRoot() - if err != nil { - isAdmin = false - } - - var wel winEventLog - if isAdmin { - src := paths.ServiceName() - - err := eventlog.InstallAsEventCreate(src, eventlog.Info|eventlog.Warning|eventlog.Error) - if err != nil && !strings.Contains(err.Error(), "registry key already exists") { - return nil, err - } - - eLog, err := eventlog.Open(src) - if err != nil { - return nil, err - } - wel = eLog - } - - return &logger{ - wel: wel, - }, nil -} - -// Close closes the event log -func (l *logger) Close() { - if l == nil || l.wel == nil { - return - } - _ = l.wel.Close() -} - -// Fatal is equivalent to [fmt.Print] followed by a call to [os.Exit](1). -func (l *logger) Fatal(v ...any) { - if l == nil { - return - } - msg := fmt.Sprint(v...) - if l.wel != nil { - _ = l.wel.Error(1, msg) - } - fmt.Println(msg) - os.Exit(1) -} - -// Fatalf is equivalent to [fmt.Printf] followed by a call to [os.Exit](1). -func (l *logger) Fatalf(format string, v ...any) { - if l == nil { - return - } - msg := fmt.Sprintf(format, v...) - if l.wel != nil { - _ = l.wel.Error(1, msg) - } - fmt.Println(msg) - os.Exit(1) -} - func main() { - log, err := newLogger() - if err != nil { - fmt.Printf("Error creating logger: %v\n", err) - os.Exit(1) - } - defer log.Close() - + log.SetFlags(0) if CommitSHA == "" { // this should never happen - log.Fatal("No commit SHA provided") + log.Fatal("No commit SHA provided\n") } exePath, err := os.Executable()