Compare commits
No commits in common. "a87c5683354a94e6d049e6d40f18a7678f133490" and "ad8499daa50cc426ccbb1fbb04d872e0612aa2ab" have entirely different histories.
a87c568335
...
ad8499daa5
@ -18,8 +18,7 @@
|
|||||||
"extensions": [
|
"extensions": [
|
||||||
"golang.go",
|
"golang.go",
|
||||||
"ms-azuretools.vscode-docker",
|
"ms-azuretools.vscode-docker",
|
||||||
"ms-vscode.makefile-tools",
|
"ms-vscode.makefile-tools"
|
||||||
"ms-vscode.cpptools-extension-pack"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,3 +1 @@
|
|||||||
/cmd/wingmate/wingmate
|
/cmd/wingmate/wingmate
|
||||||
/cmd/pidproxy/pidproxy
|
|
||||||
/cmd/exec/exec
|
|
||||||
18
Makefile
18
Makefile
@ -1,6 +1,6 @@
|
|||||||
DESTDIR = /usr/local/bin
|
|
||||||
|
|
||||||
all: wingmate dummy oneshot spawner starter pidproxy exec
|
|
||||||
|
all: wingmate dummy oneshot spawner starter pidproxy
|
||||||
|
|
||||||
wingmate:
|
wingmate:
|
||||||
$(MAKE) -C cmd/wingmate all
|
$(MAKE) -C cmd/wingmate all
|
||||||
@ -8,9 +8,6 @@ wingmate:
|
|||||||
pidproxy:
|
pidproxy:
|
||||||
$(MAKE) -C cmd/pidproxy all
|
$(MAKE) -C cmd/pidproxy all
|
||||||
|
|
||||||
exec:
|
|
||||||
$(MAKE) -C cmd/exec all
|
|
||||||
|
|
||||||
dummy:
|
dummy:
|
||||||
$(MAKE) -C cmd/experiment/dummy all
|
$(MAKE) -C cmd/experiment/dummy all
|
||||||
|
|
||||||
@ -26,18 +23,7 @@ starter:
|
|||||||
clean:
|
clean:
|
||||||
$(MAKE) -C cmd/wingmate clean
|
$(MAKE) -C cmd/wingmate clean
|
||||||
$(MAKE) -C cmd/pidproxy clean
|
$(MAKE) -C cmd/pidproxy clean
|
||||||
$(MAKE) -C cmd/exec clean
|
|
||||||
$(MAKE) -C cmd/experiment/dummy clean
|
$(MAKE) -C cmd/experiment/dummy clean
|
||||||
$(MAKE) -C cmd/experiment/oneshot clean
|
$(MAKE) -C cmd/experiment/oneshot clean
|
||||||
$(MAKE) -C cmd/experiment/spawner clean
|
$(MAKE) -C cmd/experiment/spawner clean
|
||||||
$(MAKE) -C cmd/experiment/starter clean
|
$(MAKE) -C cmd/experiment/starter clean
|
||||||
|
|
||||||
install:
|
|
||||||
install -d ${DESTDIR}
|
|
||||||
$(MAKE) -C cmd/wingmate DESTDIR=${DESTDIR} install
|
|
||||||
$(MAKE) -C cmd/pidproxy DESTDIR=${DESTDIR} install
|
|
||||||
$(MAKE) -C cmd/exec DESTDIR=${DESTDIR} install
|
|
||||||
$(MAKE) -C cmd/experiment/dummy DESTDIR=${DESTDIR} install
|
|
||||||
$(MAKE) -C cmd/experiment/oneshot DESTDIR=${DESTDIR} install
|
|
||||||
$(MAKE) -C cmd/experiment/spawner DESTDIR=${DESTDIR} install
|
|
||||||
$(MAKE) -C cmd/experiment/starter DESTDIR=${DESTDIR} install
|
|
||||||
|
|||||||
@ -1,8 +0,0 @@
|
|||||||
all:
|
|
||||||
go build -v
|
|
||||||
|
|
||||||
clean:
|
|
||||||
go clean -i -cache -testcache
|
|
||||||
|
|
||||||
install:
|
|
||||||
install exec ${DESTDIR}/wmexec
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
//go:build !(cgo && linux)
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
func getUid(user string) (uint64, error) {
|
|
||||||
panic("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func getGid(group string) (uint64, error) {
|
|
||||||
panic("not implemented")
|
|
||||||
}
|
|
||||||
@ -1,51 +0,0 @@
|
|||||||
//go:build cgo && linux
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
/*
|
|
||||||
#include<errno.h>
|
|
||||||
#include<string.h>
|
|
||||||
#include<sys/types.h>
|
|
||||||
#include<pwd.h>
|
|
||||||
#include<grp.h>
|
|
||||||
|
|
||||||
static uid_t getuid(const char* username) {
|
|
||||||
struct passwd local, *rv;
|
|
||||||
errno = 0;
|
|
||||||
rv = getpwnam(username);
|
|
||||||
if (errno != 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(&local, rv, sizeof(struct passwd));
|
|
||||||
return local.pw_uid;
|
|
||||||
}
|
|
||||||
static gid_t getgid(const char* groupname) {
|
|
||||||
struct group local, *rv;
|
|
||||||
errno = 0;
|
|
||||||
rv = getgrnam(groupname);
|
|
||||||
if (errno != 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(&local, rv, sizeof(struct group));
|
|
||||||
return local.gr_gid;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
func getUid(user string) (uint64, error) {
|
|
||||||
u, err := C.getuid(C.CString(user))
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return uint64(u), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getGid(group string) (uint64, error) {
|
|
||||||
g, err := C.getgid(C.CString(group))
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return uint64(g), nil
|
|
||||||
}
|
|
||||||
133
cmd/exec/exec.go
133
cmd/exec/exec.go
@ -1,133 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"gitea.suyono.dev/suyono/wingmate"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
setsidFlag = "setsid"
|
|
||||||
EnvSetsid = "SETSID"
|
|
||||||
userFlag = "user"
|
|
||||||
EnvUser = "USER"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
rootCmd = &cobra.Command{
|
|
||||||
Use: "wmexec",
|
|
||||||
RunE: execCmd,
|
|
||||||
}
|
|
||||||
|
|
||||||
childArgs []string
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
var (
|
|
||||||
found bool
|
|
||||||
i int
|
|
||||||
arg string
|
|
||||||
selfArgs []string
|
|
||||||
)
|
|
||||||
|
|
||||||
rootCmd.PersistentFlags().BoolP(setsidFlag, "s", false, "set to true to run setsid() before exec")
|
|
||||||
viper.BindPFlag(EnvSetsid, rootCmd.PersistentFlags().Lookup(setsidFlag))
|
|
||||||
|
|
||||||
rootCmd.PersistentFlags().StringP(userFlag, "u", "", "\"user:[group]\"")
|
|
||||||
viper.BindPFlag(EnvUser, rootCmd.PersistentFlags().Lookup(userFlag))
|
|
||||||
|
|
||||||
viper.SetEnvPrefix(wingmate.EnvPrefix)
|
|
||||||
viper.BindEnv(EnvUser)
|
|
||||||
viper.BindEnv(EnvSetsid)
|
|
||||||
viper.SetDefault(EnvSetsid, false)
|
|
||||||
viper.SetDefault(EnvUser, "")
|
|
||||||
|
|
||||||
found = false
|
|
||||||
for i, arg = range os.Args {
|
|
||||||
if arg == "--" {
|
|
||||||
found = true
|
|
||||||
if len(os.Args) <= i+1 {
|
|
||||||
log.Println("invalid argument")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
selfArgs = os.Args[1:i]
|
|
||||||
childArgs = os.Args[i+1:]
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
log.Println("invalid argument")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(childArgs) == 0 {
|
|
||||||
log.Println("invalid argument")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
rootCmd.SetArgs(selfArgs)
|
|
||||||
if err := rootCmd.Execute(); err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func execCmd(cmd *cobra.Command, args []string) error {
|
|
||||||
if viper.GetBool(EnvSetsid) {
|
|
||||||
_, _ = unix.Setsid()
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
uid uint64
|
|
||||||
gid uint64
|
|
||||||
err error
|
|
||||||
path string
|
|
||||||
)
|
|
||||||
|
|
||||||
ug := viper.GetString(EnvUser)
|
|
||||||
if len(ug) > 0 {
|
|
||||||
user, group, ok := strings.Cut(ug, ":")
|
|
||||||
if ok {
|
|
||||||
if gid, err = strconv.ParseUint(group, 10, 32); err != nil {
|
|
||||||
if gid, err = getGid(group); err != nil {
|
|
||||||
return fmt.Errorf("cgo getgid: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err = unix.Setgid(int(gid)); err != nil {
|
|
||||||
return fmt.Errorf("setgid: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uid, err = strconv.ParseUint(user, 10, 32)
|
|
||||||
if err != nil {
|
|
||||||
if uid, err = getUid(user); err != nil {
|
|
||||||
return fmt.Errorf("cgo getuid: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err = unix.Setuid(int(uid)); err != nil {
|
|
||||||
return fmt.Errorf("setuid: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if path, err = exec.LookPath(childArgs[0]); err != nil {
|
|
||||||
if !errors.Is(err, exec.ErrDot) {
|
|
||||||
return fmt.Errorf("lookpath: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = unix.Exec(path, childArgs, os.Environ()); err != nil {
|
|
||||||
return fmt.Errorf("exec: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@ -3,6 +3,3 @@ all:
|
|||||||
|
|
||||||
clean:
|
clean:
|
||||||
go clean -i -cache -testcache
|
go clean -i -cache -testcache
|
||||||
|
|
||||||
install:
|
|
||||||
install dummy ${DESTDIR}/wmdummy
|
|
||||||
@ -3,6 +3,3 @@ all:
|
|||||||
|
|
||||||
clean:
|
clean:
|
||||||
go clean -i -cache -testcache
|
go clean -i -cache -testcache
|
||||||
|
|
||||||
install:
|
|
||||||
install oneshot ${DESTDIR}/wmoneshot
|
|
||||||
@ -3,6 +3,3 @@ all:
|
|||||||
|
|
||||||
clean:
|
clean:
|
||||||
go clean -i -cache -testcache
|
go clean -i -cache -testcache
|
||||||
|
|
||||||
install:
|
|
||||||
install spawner ${DESTDIR}/wmspawner
|
|
||||||
@ -3,6 +3,3 @@ all:
|
|||||||
|
|
||||||
clean:
|
clean:
|
||||||
go clean -i -cache -testcache
|
go clean -i -cache -testcache
|
||||||
|
|
||||||
install:
|
|
||||||
install starter ${DESTDIR}/wmstarter
|
|
||||||
@ -3,6 +3,3 @@ all:
|
|||||||
|
|
||||||
clean:
|
clean:
|
||||||
go clean -i -cache -testcache
|
go clean -i -cache -testcache
|
||||||
|
|
||||||
install:
|
|
||||||
install pidproxy ${DESTDIR}/wmpidproxy
|
|
||||||
@ -4,7 +4,6 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"os/signal"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
@ -42,6 +41,11 @@ func main() {
|
|||||||
viper.BindEnv(EnvStartSecs)
|
viper.BindEnv(EnvStartSecs)
|
||||||
viper.SetDefault(EnvStartSecs, EnvDefaultStartSecs)
|
viper.SetDefault(EnvStartSecs, EnvDefaultStartSecs)
|
||||||
|
|
||||||
|
if len(os.Args) <= 2 {
|
||||||
|
log.Println("invalid argument")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
rootCmd.PersistentFlags().StringP(pidFileFlag, "p", "", "location of pid file")
|
rootCmd.PersistentFlags().StringP(pidFileFlag, "p", "", "location of pid file")
|
||||||
rootCmd.MarkFlagRequired(pidFileFlag)
|
rootCmd.MarkFlagRequired(pidFileFlag)
|
||||||
viper.BindPFlag(pidFileFlag, rootCmd.PersistentFlags().Lookup(pidFileFlag))
|
viper.BindPFlag(pidFileFlag, rootCmd.PersistentFlags().Lookup(pidFileFlag))
|
||||||
@ -50,11 +54,11 @@ func main() {
|
|||||||
for i, arg = range os.Args {
|
for i, arg = range os.Args {
|
||||||
if arg == "--" {
|
if arg == "--" {
|
||||||
found = true
|
found = true
|
||||||
|
selfArgs = os.Args[1:i]
|
||||||
if len(os.Args) <= i+1 {
|
if len(os.Args) <= i+1 {
|
||||||
log.Println("invalid argument")
|
log.Println("invalid argument")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
selfArgs = os.Args[1:i]
|
|
||||||
childArgs = os.Args[i+1:]
|
childArgs = os.Args[i+1:]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -64,11 +68,6 @@ func main() {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(childArgs) == 0 {
|
|
||||||
log.Println("invalid argument")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
rootCmd.SetArgs(selfArgs)
|
rootCmd.SetArgs(selfArgs)
|
||||||
|
|
||||||
if err := rootCmd.Execute(); err != nil {
|
if err := rootCmd.Execute(); err != nil {
|
||||||
@ -91,16 +90,7 @@ func pidProxy(cmd *cobra.Command, args []string) error {
|
|||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
pid int
|
pid int
|
||||||
sc chan os.Signal
|
|
||||||
t *time.Timer
|
|
||||||
)
|
)
|
||||||
|
|
||||||
sc = make(chan os.Signal, 1)
|
|
||||||
signal.Notify(sc, unix.SIGTERM)
|
|
||||||
|
|
||||||
t = time.NewTimer(time.Second)
|
|
||||||
|
|
||||||
check:
|
|
||||||
for {
|
for {
|
||||||
if pid, err = readPid(pidfile); err != nil {
|
if pid, err = readPid(pidfile); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -110,20 +100,8 @@ check:
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
select {
|
time.Sleep(time.Second)
|
||||||
case <-t.C:
|
|
||||||
case <-sc:
|
|
||||||
if pid, err = readPid(pidfile); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = unix.Kill(pid, unix.SIGTERM); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
break check
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func readPid(pidFile string) (int, error) {
|
func readPid(pidFile string) (int, error) {
|
||||||
|
|||||||
@ -3,7 +3,3 @@ all:
|
|||||||
|
|
||||||
clean:
|
clean:
|
||||||
go clean -i -cache -testcache
|
go clean -i -cache -testcache
|
||||||
|
|
||||||
install:
|
|
||||||
install wingmate ${DESTDIR}/wingmate
|
|
||||||
|
|
||||||
@ -7,7 +7,6 @@ import (
|
|||||||
|
|
||||||
"gitea.suyono.dev/suyono/wingmate"
|
"gitea.suyono.dev/suyono/wingmate"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -49,11 +48,8 @@ func Read() (*Config, error) {
|
|||||||
if len(dirent) > 0 {
|
if len(dirent) > 0 {
|
||||||
for _, d := range dirent {
|
for _, d := range dirent {
|
||||||
if d.Type().IsRegular() {
|
if d.Type().IsRegular() {
|
||||||
svcPath := filepath.Join(svcdir, d.Name())
|
|
||||||
if err = unix.Access(svcPath, unix.X_OK); err == nil {
|
|
||||||
serviceAvailable = true
|
serviceAvailable = true
|
||||||
outConfig.ServicePaths = append(outConfig.ServicePaths, svcPath)
|
outConfig.ServicePaths = append(outConfig.ServicePaths, filepath.Join(svcdir, d.Name()))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,130 +0,0 @@
|
|||||||
package config
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"gitea.suyono.dev/suyono/wingmate"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestRead(t *testing.T) {
|
|
||||||
|
|
||||||
type testEntry struct {
|
|
||||||
name string
|
|
||||||
testFunc func(t *testing.T)
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
configDir string
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
|
|
||||||
const serviceDir = "service"
|
|
||||||
|
|
||||||
setup := func(t *testing.T) {
|
|
||||||
if configDir, err = os.MkdirTemp("", "wingmate-*-test"); err != nil {
|
|
||||||
t.Fatal("setup", err)
|
|
||||||
}
|
|
||||||
viper.Set(EnvConfigPath, configDir)
|
|
||||||
}
|
|
||||||
|
|
||||||
tear := func(t *testing.T) {
|
|
||||||
if err = os.RemoveAll(configDir); err != nil {
|
|
||||||
t.Fatal("tear", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mkSvcDir := func(t *testing.T) {
|
|
||||||
if err := os.MkdirAll(path.Join(configDir, serviceDir), 0755); err != nil {
|
|
||||||
t.Fatal("create dir", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
touchFile := func(t *testing.T, name string, perm os.FileMode) {
|
|
||||||
f, err := os.OpenFile(name, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, perm)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal("create file", err)
|
|
||||||
}
|
|
||||||
_ = f.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
_ = wingmate.NewLog(os.Stderr)
|
|
||||||
tests := []testEntry{
|
|
||||||
{
|
|
||||||
name: "positive",
|
|
||||||
testFunc: func(t *testing.T) {
|
|
||||||
mkSvcDir(t)
|
|
||||||
touchFile(t, path.Join(configDir, serviceDir, "one.sh"), 0755)
|
|
||||||
touchFile(t, path.Join(configDir, serviceDir, "two.sh"), 0755)
|
|
||||||
|
|
||||||
cfg, err := Read()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.ElementsMatch(
|
|
||||||
t,
|
|
||||||
cfg.ServicePaths,
|
|
||||||
[]string{
|
|
||||||
path.Join(configDir, serviceDir, "one.sh"),
|
|
||||||
path.Join(configDir, serviceDir, "two.sh"),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "with directory",
|
|
||||||
testFunc: func(t *testing.T) {
|
|
||||||
const subdir1 = "subdir1"
|
|
||||||
mkSvcDir(t)
|
|
||||||
assert.Nil(t, os.Mkdir(path.Join(configDir, serviceDir, subdir1), 0755))
|
|
||||||
touchFile(t, path.Join(configDir, serviceDir, subdir1, "one.sh"), 0755)
|
|
||||||
touchFile(t, path.Join(configDir, serviceDir, "two.sh"), 0755)
|
|
||||||
cfg, err := Read()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.ElementsMatch(
|
|
||||||
t,
|
|
||||||
cfg.ServicePaths,
|
|
||||||
[]string{
|
|
||||||
path.Join(configDir, serviceDir, "two.sh"),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "wrong mode",
|
|
||||||
testFunc: func(t *testing.T) {
|
|
||||||
mkSvcDir(t)
|
|
||||||
touchFile(t, path.Join(configDir, serviceDir, "one.sh"), 0755)
|
|
||||||
touchFile(t, path.Join(configDir, serviceDir, "two.sh"), 0644)
|
|
||||||
|
|
||||||
cfg, err := Read()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.ElementsMatch(
|
|
||||||
t,
|
|
||||||
cfg.ServicePaths,
|
|
||||||
[]string{
|
|
||||||
path.Join(configDir, serviceDir, "one.sh"),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "empty",
|
|
||||||
testFunc: func(t *testing.T) {
|
|
||||||
mkSvcDir(t)
|
|
||||||
|
|
||||||
_, err := Read()
|
|
||||||
assert.NotNil(t, err)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
setup(t)
|
|
||||||
tt.testFunc(t)
|
|
||||||
tear(t)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -2,16 +2,19 @@ FROM golang:1.21-alpine as builder
|
|||||||
|
|
||||||
ADD . /root/wingmate
|
ADD . /root/wingmate
|
||||||
WORKDIR /root/wingmate/
|
WORKDIR /root/wingmate/
|
||||||
RUN apk add make build-base && CGO_ENABLED=1 make all && make DESTDIR=/usr/local/bin/wingmate install
|
RUN apk add make && make all
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
FROM alpine:3.18
|
FROM alpine:3.18
|
||||||
|
|
||||||
RUN apk add tzdata && ln -s /usr/share/zoneinfo/Australia/Sydney /etc/localtime && \
|
RUN apk add tzdata && ln -s /usr/share/zoneinfo/Australia/Sydney /etc/localtime
|
||||||
adduser -h /home/user1 -D -s /bin/sh user1 && \
|
COPY --from=builder /root/wingmate/cmd/wingmate/wingmate /usr/local/bin/wingmate
|
||||||
adduser -h /home/user2 -D -s /bin/sh user2
|
COPY --from=builder /root/wingmate/cmd/experiment/dummy/dummy /usr/local/bin/wmdummy
|
||||||
COPY --from=builder /usr/local/bin/wingmate/ /usr/local/bin/
|
COPY --from=builder /root/wingmate/cmd/experiment/starter/starter /usr/local/bin/wmstarter
|
||||||
|
COPY --from=builder /root/wingmate/cmd/experiment/oneshot/oneshot /usr/local/bin/wmoneshot
|
||||||
|
COPY --from=builder /root/wingmate/cmd/experiment/spawner/spawner /usr/local/bin/wmspawner
|
||||||
|
COPY --from=builder /root/wingmate/cmd/pidproxy/pidproxy /usr/local/bin/wmpidproxy
|
||||||
ADD --chmod=755 docker/alpine/entry.sh /usr/local/bin/entry.sh
|
ADD --chmod=755 docker/alpine/entry.sh /usr/local/bin/entry.sh
|
||||||
ADD --chmod=755 docker/alpine/etc /etc
|
ADD --chmod=755 docker/alpine/etc /etc
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
export DUMMY_PATH=/usr/local/bin/wmdummy
|
export DUMMY_PATH=/usr/local/bin/wmdummy
|
||||||
exec /usr/local/bin/wmexec --setsid --user user1:user1 -- /usr/local/bin/wmstarter
|
exec /usr/local/bin/wmstarter
|
||||||
@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
export WINGMATE_ONESHOT_PATH=/usr/local/bin/wmoneshot
|
export WINGMATE_ONESHOT_PATH=/usr/local/bin/wmoneshot
|
||||||
export WINGMATE_DUMMY_PATH=/usr/local/bin/wmdummy
|
export WINGMATE_DUMMY_PATH=/usr/local/bin/wmdummy
|
||||||
exec /usr/local/bin/wmexec --user 1001 -- /usr/local/bin/wmspawner
|
exec /usr/local/bin/wmspawner
|
||||||
@ -2,16 +2,19 @@ FROM golang:1.21-bookworm as builder
|
|||||||
|
|
||||||
ADD . /root/wingmate
|
ADD . /root/wingmate
|
||||||
WORKDIR /root/wingmate/
|
WORKDIR /root/wingmate/
|
||||||
RUN make all && make DESTDIR=/usr/local/bin/wingmate install
|
RUN make all
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
FROM debian:bookworm
|
FROM debian:bookworm
|
||||||
|
|
||||||
RUN ln -sf /usr/share/zoneinfo/Australia/Sydney /etc/localtime && \
|
RUN ln -sf /usr/share/zoneinfo/Australia/Sydney /etc/localtime
|
||||||
apt update && apt install -y procps && \
|
COPY --from=builder /root/wingmate/cmd/wingmate/wingmate /usr/local/bin/wingmate
|
||||||
useradd -m -s /bin/bash user1
|
COPY --from=builder /root/wingmate/cmd/experiment/dummy/dummy /usr/local/bin/wmdummy
|
||||||
COPY --from=builder /usr/local/bin/wingmate/ /usr/local/bin/
|
COPY --from=builder /root/wingmate/cmd/experiment/starter/starter /usr/local/bin/wmstarter
|
||||||
|
COPY --from=builder /root/wingmate/cmd/experiment/oneshot/oneshot /usr/local/bin/wmoneshot
|
||||||
|
COPY --from=builder /root/wingmate/cmd/experiment/spawner/spawner /usr/local/bin/wmspawner
|
||||||
|
COPY --from=builder /root/wingmate/cmd/pidproxy/pidproxy /usr/local/bin/wmpidproxy
|
||||||
ADD --chmod=755 docker/bookworm/entry.sh /usr/local/bin/entry.sh
|
ADD --chmod=755 docker/bookworm/entry.sh /usr/local/bin/entry.sh
|
||||||
ADD --chmod=755 docker/bookworm/etc /etc
|
ADD --chmod=755 docker/bookworm/etc /etc
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/bash
|
#!/usr/bin/bash
|
||||||
|
|
||||||
export DUMMY_PATH=/usr/local/bin/wmdummy
|
export DUMMY_PATH=/usr/local/bin/wmdummy
|
||||||
exec /usr/local/bin/wmexec --setsid --user user1:user1 -- /usr/local/bin/wmstarter
|
exec /usr/local/bin/wmstarter
|
||||||
@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
export WINGMATE_ONESHOT_PATH=/usr/local/bin/wmoneshot
|
export WINGMATE_ONESHOT_PATH=/usr/local/bin/wmoneshot
|
||||||
export WINGMATE_DUMMY_PATH=/usr/local/bin/wmdummy
|
export WINGMATE_DUMMY_PATH=/usr/local/bin/wmdummy
|
||||||
exec /usr/local/bin/wmexec --user 1200 -- /usr/local/bin/wmspawner
|
exec /usr/local/bin/wmspawner
|
||||||
1
go.mod
1
go.mod
@ -28,7 +28,6 @@ require (
|
|||||||
github.com/spf13/cast v1.6.0 // indirect
|
github.com/spf13/cast v1.6.0 // indirect
|
||||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/stretchr/objx v0.5.1 // indirect
|
|
||||||
github.com/subosito/gotenv v1.6.0 // indirect
|
github.com/subosito/gotenv v1.6.0 // indirect
|
||||||
go.uber.org/atomic v1.11.0 // indirect
|
go.uber.org/atomic v1.11.0 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
|
|||||||
3
go.sum
3
go.sum
@ -201,15 +201,12 @@ github.com/spf13/viper v1.17.0/go.mod h1:BmMMMLQXSbcHK6KAOiFLz0l5JHrU89OdIRHvsk0
|
|||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/objx v0.5.1 h1:4VhoImhV/Bm0ToFkXFi8hXNXwpDRZ/ynw3amt82mzq0=
|
|
||||||
github.com/stretchr/objx v0.5.1/go.mod h1:/iHQpkQwBD6DLUmQ4pE+s1TXdob1mORJ4/UFdrifcy0=
|
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
package init
|
package init
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -35,19 +34,17 @@ func (i *Init) Start() {
|
|||||||
wg *sync.WaitGroup
|
wg *sync.WaitGroup
|
||||||
signalTrigger chan any
|
signalTrigger chan any
|
||||||
sighandlerExit chan any
|
sighandlerExit chan any
|
||||||
sigchld chan os.Signal
|
|
||||||
)
|
)
|
||||||
|
|
||||||
signalTrigger = make(chan any)
|
signalTrigger = make(chan any)
|
||||||
sighandlerExit = make(chan any)
|
sighandlerExit = make(chan any)
|
||||||
sigchld = make(chan os.Signal, 1)
|
|
||||||
|
|
||||||
wg = &sync.WaitGroup{}
|
wg = &sync.WaitGroup{}
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go i.waiter(wg, signalTrigger, sighandlerExit, sigchld)
|
go i.waiter(wg, signalTrigger, sighandlerExit)
|
||||||
|
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go i.sighandler(wg, signalTrigger, sighandlerExit, sigchld)
|
go i.sighandler(wg, signalTrigger, sighandlerExit)
|
||||||
|
|
||||||
for _, s := range i.config.Services() {
|
for _, s := range i.config.Services() {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import (
|
|||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (i *Init) sighandler(wg *sync.WaitGroup, trigger chan<- any, selfExit <-chan any, sigchld chan<- os.Signal) {
|
func (i *Init) sighandler(wg *sync.WaitGroup, trigger chan<- any, selfExit <-chan any) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -35,10 +35,7 @@ signal:
|
|||||||
isOpen = false
|
isOpen = false
|
||||||
}
|
}
|
||||||
case unix.SIGCHLD:
|
case unix.SIGCHLD:
|
||||||
select {
|
// do nothing
|
||||||
case sigchld <- s:
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case <-selfExit:
|
case <-selfExit:
|
||||||
|
|||||||
@ -2,20 +2,20 @@ package init
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"os"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"gitea.suyono.dev/suyono/wingmate"
|
"gitea.suyono.dev/suyono/wingmate"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (i *Init) waiter(wg *sync.WaitGroup, runningFlag <-chan any, sigHandlerFlag chan<- any, sigchld <-chan os.Signal) {
|
func (i *Init) waiter(wg *sync.WaitGroup, runningFlag <-chan any, sigHandlerFlag chan<- any) {
|
||||||
var (
|
var (
|
||||||
ws unix.WaitStatus
|
ws unix.WaitStatus
|
||||||
|
// pid int
|
||||||
err error
|
err error
|
||||||
running bool
|
running bool
|
||||||
flagged bool
|
flagged bool
|
||||||
waitingForSignal bool
|
|
||||||
)
|
)
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|
||||||
@ -25,28 +25,15 @@ func (i *Init) waiter(wg *sync.WaitGroup, runningFlag <-chan any, sigHandlerFlag
|
|||||||
|
|
||||||
running = true
|
running = true
|
||||||
flagged = true
|
flagged = true
|
||||||
waitingForSignal = true
|
|
||||||
wait:
|
wait:
|
||||||
for {
|
for {
|
||||||
if running {
|
if running {
|
||||||
if waitingForSignal {
|
|
||||||
select {
|
|
||||||
case <-runningFlag:
|
|
||||||
wingmate.Log().Info().Msg("waiter received shutdown signal...")
|
|
||||||
running = false
|
|
||||||
case <-sigchld:
|
|
||||||
waitingForSignal = false
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
select {
|
select {
|
||||||
case <-runningFlag:
|
case <-runningFlag:
|
||||||
wingmate.Log().Info().Msg("waiter received shutdown signal...")
|
wingmate.Log().Info().Msg("waiter received shutdown signal...")
|
||||||
running = false
|
running = false
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = unix.Wait4(-1, &ws, 0, nil); err != nil {
|
if _, err = unix.Wait4(-1, &ws, 0, nil); err != nil {
|
||||||
@ -63,7 +50,7 @@ wait:
|
|||||||
}
|
}
|
||||||
|
|
||||||
wingmate.Log().Warn().Msgf("Wait4 returns error: %+v", err)
|
wingmate.Log().Warn().Msgf("Wait4 returns error: %+v", err)
|
||||||
waitingForSignal = true
|
time.Sleep(time.Millisecond * 100)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user