Using go entrypoint for Windows agents

This commit is contained in:
Alexey Pustovalov 2026-07-15 18:17:22 +09:00
parent 0866f929e2
commit cfdc5b9519
8 changed files with 0 additions and 199 deletions

View file

@ -10,8 +10,6 @@
!templates/entrypoints/internal/agent/** !templates/entrypoints/internal/agent/**
!templates/entrypoints/internal/bootstrap/ !templates/entrypoints/internal/bootstrap/
!templates/entrypoints/internal/bootstrap/** !templates/entrypoints/internal/bootstrap/**
!templates/entrypoints/internal/hooks/
!templates/entrypoints/internal/hooks/**
!templates/entrypoints/licenses/ !templates/entrypoints/licenses/
!templates/entrypoints/licenses/go-THIRD-PARTY-NOTICES.txt !templates/entrypoints/licenses/go-THIRD-PARTY-NOTICES.txt
!templates/config/ !templates/config/

View file

@ -10,8 +10,6 @@
!templates/entrypoints/internal/agent/** !templates/entrypoints/internal/agent/**
!templates/entrypoints/internal/bootstrap/ !templates/entrypoints/internal/bootstrap/
!templates/entrypoints/internal/bootstrap/** !templates/entrypoints/internal/bootstrap/**
!templates/entrypoints/internal/hooks/
!templates/entrypoints/internal/hooks/**
!templates/entrypoints/licenses/ !templates/entrypoints/licenses/
!templates/entrypoints/licenses/go-THIRD-PARTY-NOTICES.txt !templates/entrypoints/licenses/go-THIRD-PARTY-NOTICES.txt
!templates/config/ !templates/config/

View file

@ -5,7 +5,6 @@ package main
import ( import (
config "github.com/zabbix/zabbix-docker/templates/entrypoints/internal/agent" config "github.com/zabbix/zabbix-docker/templates/entrypoints/internal/agent"
"github.com/zabbix/zabbix-docker/templates/entrypoints/internal/bootstrap" "github.com/zabbix/zabbix-docker/templates/entrypoints/internal/bootstrap"
"github.com/zabbix/zabbix-docker/templates/entrypoints/internal/hooks"
) )
func prepareService(env bootstrap.Environment) error { func prepareService(env bootstrap.Environment) error {
@ -26,10 +25,6 @@ func prepareService(env bootstrap.Environment) error {
return err return err
} }
if err := hooks.Run(env); err != nil {
return err
}
config.ClearPrivateEnv(env) config.ClearPrivateEnv(env)
return nil return nil

View file

@ -8,7 +8,6 @@ import (
config "github.com/zabbix/zabbix-docker/templates/entrypoints/internal/agent" config "github.com/zabbix/zabbix-docker/templates/entrypoints/internal/agent"
"github.com/zabbix/zabbix-docker/templates/entrypoints/internal/bootstrap" "github.com/zabbix/zabbix-docker/templates/entrypoints/internal/bootstrap"
"github.com/zabbix/zabbix-docker/templates/entrypoints/internal/hooks"
) )
func prepareService(env bootstrap.Environment) error { func prepareService(env bootstrap.Environment) error {
@ -34,10 +33,6 @@ func prepareService(env bootstrap.Environment) error {
return err return err
} }
if err := hooks.Run(env); err != nil {
return err
}
config.ClearPrivateEnv(env) config.ClearPrivateEnv(env)
return nil return nil

View file

@ -1,18 +0,0 @@
package hooks
import (
"os"
"path/filepath"
"strings"
)
func command(path string, _ os.FileMode) ([]string, bool) {
switch strings.ToLower(filepath.Ext(path)) {
case ".ps1":
return []string{"pwsh.exe", "-NoLogo", "-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-File", path}, true
case ".cmd", ".bat":
return []string{"cmd.exe", "/D", "/S", "/C", path}, true
default:
return nil, false
}
}

View file

@ -1,27 +0,0 @@
//go:build windows
package hooks
import (
"os"
"reflect"
"testing"
)
func TestPowerShellCommand(t *testing.T) {
path := `C:\zabbix\entrypoint.d\10-custom.ps1`
args, supported := command(path, os.FileMode(0))
want := []string{"pwsh.exe", "-NoLogo", "-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-File", path}
if !supported || !reflect.DeepEqual(args, want) {
t.Fatalf("command() = %#v, %v; want %#v, true", args, supported, want)
}
}
func TestCmdCommand(t *testing.T) {
path := `C:\zabbix\entrypoint.d\20-custom.cmd`
args, supported := command(path, os.FileMode(0))
want := []string{"cmd.exe", "/D", "/S", "/C", path}
if !supported || !reflect.DeepEqual(args, want) {
t.Fatalf("command() = %#v, %v; want %#v, true", args, supported, want)
}
}

View file

@ -1,64 +0,0 @@
//go:build windows
// Package hooks runs user-provided scripts from the entrypoint.d directory
// before the service starts.
package hooks
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"github.com/zabbix/zabbix-docker/templates/entrypoints/internal/bootstrap"
)
const directoryName = "entrypoint.d"
// Run executes supported PowerShell and cmd scripts from <home>/entrypoint.d
// in file name order. Everything else is skipped. The first failing hook
// aborts the entrypoint.
func Run(env bootstrap.Environment) error {
homeDir, err := bootstrap.RequiredHomeDirectory(env)
if err != nil {
return err
}
directory := filepath.Join(homeDir, directoryName)
entries, err := os.ReadDir(directory)
if os.IsNotExist(err) {
return nil
}
if err != nil {
return fmt.Errorf("read entrypoint hooks directory %s: %w", directory, err)
}
for _, entry := range entries {
path := filepath.Join(directory, entry.Name())
info, err := os.Stat(path)
if err != nil {
return fmt.Errorf("inspect entrypoint hook %s: %w", path, err)
}
if !info.Mode().IsRegular() {
continue
}
args, supported := command(path, info.Mode())
if !supported {
continue
}
bootstrap.LogInfo("** Running entrypoint hook: %s", path)
hook := exec.Command(args[0], args[1:]...)
hook.Env = env.List()
hook.Stdin = os.Stdin
hook.Stdout = os.Stdout
hook.Stderr = os.Stderr
if err := hook.Run(); err != nil {
return fmt.Errorf("entrypoint hook %s failed: %w", path, err)
}
}
return nil
}

View file

@ -1,76 +0,0 @@
//go:build windows
package hooks
import (
"os"
"path/filepath"
"strings"
"testing"
"github.com/zabbix/zabbix-docker/templates/entrypoints/internal/bootstrap"
)
func TestRunExecutesHooksInOrder(t *testing.T) {
homeDir := t.TempDir()
directory := filepath.Join(homeDir, directoryName)
if err := os.Mkdir(directory, 0o700); err != nil {
t.Fatal(err)
}
output := filepath.Join(homeDir, "output")
for name, content := range map[string]string{
"20-second.cmd": "@echo second:%ZABBIX_CONF_DIR%>>\"%HOOK_OUTPUT%\"\r\n",
"10-first.cmd": "@echo first:%ZABBIX_CONF_DIR%>>\"%HOOK_OUTPUT%\"\r\n",
"30-ignored.txt": "@exit /b 1\r\n",
} {
if err := os.WriteFile(filepath.Join(directory, name), []byte(content), 0o600); err != nil {
t.Fatal(err)
}
}
env := bootstrap.NewEnvironment(os.Environ())
env["ZABBIX_USER_HOME_DIR"] = homeDir
env["ZABBIX_CONF_DIR"] = `C:\zabbix\conf`
env["HOOK_OUTPUT"] = output
if err := Run(env); err != nil {
t.Fatal(err)
}
data, err := os.ReadFile(output)
if err != nil {
t.Fatal(err)
}
got := strings.ReplaceAll(string(data), "\r\n", "\n")
want := "first:C:\\zabbix\\conf\nsecond:C:\\zabbix\\conf\n"
if got != want {
t.Fatalf("hook output = %q, want %q", got, want)
}
}
func TestRunReturnsHookFailure(t *testing.T) {
homeDir := t.TempDir()
directory := filepath.Join(homeDir, directoryName)
if err := os.Mkdir(directory, 0o700); err != nil {
t.Fatal(err)
}
path := filepath.Join(directory, "10-fail.cmd")
if err := os.WriteFile(path, []byte("@exit /b 7\r\n"), 0o600); err != nil {
t.Fatal(err)
}
env := bootstrap.NewEnvironment(os.Environ())
env["ZABBIX_USER_HOME_DIR"] = homeDir
err := Run(env)
if err == nil || !strings.Contains(err.Error(), "10-fail.cmd") {
t.Fatalf("unexpected error: %v", err)
}
}
func TestRunIgnoresMissingDirectory(t *testing.T) {
err := Run(bootstrap.Environment{"ZABBIX_USER_HOME_DIR": t.TempDir()})
if err != nil {
t.Fatal(err)
}
}