Skip to content

Commit 6ddaf00

Browse files
committed
Create watcher subprocess with a new Console on windows
1 parent 5ba3caf commit 6ddaf00

File tree

4 files changed

+27
-6
lines changed

4 files changed

+27
-6
lines changed

internal/pkg/agent/application/upgrade/rollback.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ func InvokeWatcher(log *logger.Logger, agentExecutable string) (*exec.Cmd, error
161161

162162
go func() {
163163
if err := cmd.Wait(); err != nil {
164-
log.Infow("Upgrade Watcher exited with error", "agent.upgrade.watcher.process.pid", "agent.process.pid", agentPID, upgradeWatcherPID, "error.message", err)
164+
log.Infow("Upgrade Watcher exited with error", "agent.upgrade.watcher.process.pid", agentPID, "agent.process.pid", upgradeWatcherPID, "error.message", err)
165165
}
166166
}()
167167

internal/pkg/agent/application/upgrade/rollback_windows.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ package upgrade
88

99
import (
1010
"os/exec"
11+
"syscall"
1112
"time"
1213

14+
"golang.org/x/sys/windows"
15+
1316
"github.com/elastic/elastic-agent/internal/pkg/agent/application/paths"
1417
)
1518

@@ -25,5 +28,23 @@ func invokeCmd(agentExecutable string) *exec.Cmd {
2528
"--path.config", paths.Config(),
2629
"--path.home", paths.Top(),
2730
)
31+
32+
cmd.SysProcAttr = &syscall.SysProcAttr{
33+
// Signals are sent to process groups, and child process are part of the
34+
// parent's prcoess group. So to send a signal to a
35+
// child process and not have it also affect ourselves
36+
// (the parent process), the child needs to be created in a new
37+
// process group.
38+
//
39+
// Creating a child with CREATE_NEW_PROCESS_GROUP disables CTLR_C_EVENT
40+
// handling for the child, so the only way to gracefully stop it is with
41+
// a CTRL_BREAK_EVENT signal.
42+
// https://learn.microsoft.com/en-us/windows/win32/procthread/process-creation-flags
43+
//
44+
// Watcher process will also need a console in order to receive CTRL_BREAK_EVENT on windows.
45+
// Elastic Agent main process running as a service does not have a console allocated and the watcher process will also
46+
// outlive its parent during an upgrade operation so we add the CREATE_NEW_CONSOLE flag.
47+
CreationFlags: windows.CREATE_NEW_PROCESS_GROUP & windows.CREATE_NEW_CONSOLE,
48+
}
2849
return cmd
2950
}

internal/pkg/agent/application/upgrade/step_relink.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ import (
1515
)
1616

1717
const (
18-
windows = "windows"
19-
exe = ".exe"
18+
windowsOSName = "windows"
19+
exe = ".exe"
2020
)
2121

2222
func changeSymlink(log *logger.Logger, topDirPath, symlinkPath, newTarget string) error {
2323

2424
// handle windows suffixes
25-
if runtime.GOOS == windows {
25+
if runtime.GOOS == windowsOSName {
2626
symlinkPath += exe
2727
newTarget += exe
2828
}
@@ -47,7 +47,7 @@ func prevSymlinkPath(topDirPath string) string {
4747
agentPrevName := agentName + ".prev"
4848

4949
// handle windows suffixes
50-
if runtime.GOOS == windows {
50+
if runtime.GOOS == windowsOSName {
5151
agentPrevName = agentName + ".exe.prev"
5252
}
5353

internal/pkg/agent/application/upgrade/step_unpack.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ func (u *Upgrader) unpack(version, archivePath, dataDir string, flavor string) (
4141
// or the extraction will be double nested
4242
var unpackRes UnpackResult
4343
var err error
44-
if runtime.GOOS == windows {
44+
if runtime.GOOS == windowsOSName {
4545
unpackRes, err = unzip(u.log, archivePath, dataDir, flavor)
4646
} else {
4747
unpackRes, err = untar(u.log, archivePath, dataDir, flavor)

0 commit comments

Comments
 (0)