Using go entrypoint for Windows agents
This commit is contained in:
parent
0866f929e2
commit
cfdc5b9519
|
|
@ -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/
|
||||||
|
|
|
||||||
|
|
@ -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/
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in a new issue