test: prepare
This commit is contained in:
parent
d5eb872b13
commit
dd66cb9f1e
2
cmd/experiment/.gitignore
vendored
2
cmd/experiment/.gitignore
vendored
@ -1,2 +1,4 @@
|
||||
/dummy/dummy
|
||||
/starter/starter
|
||||
/oneshot/oneshot
|
||||
/spawner/spawner
|
||||
67
cmd/experiment/oneshot/oneshot.go
Normal file
67
cmd/experiment/oneshot/oneshot.go
Normal file
@ -0,0 +1,67 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"math/rand"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"gitea.suyono.dev/suyono/wingmate"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
const (
|
||||
// DummyPath = "/workspaces/wingmate/cmd/experiment/dummy/dummy"
|
||||
DummyPath = "/usr/local/bin/wmdummy"
|
||||
EnvDummyPath = "DUMMY_PATH"
|
||||
EnvPrefix = "WINGMATE"
|
||||
EnvLog = "LOG"
|
||||
EnvLogMessage = "LOG_MESSAGE"
|
||||
EnvDefaultLogMessage = "oneshot executed"
|
||||
)
|
||||
|
||||
func main() {
|
||||
viper.SetEnvPrefix(EnvPrefix)
|
||||
viper.BindEnv(EnvDummyPath, EnvLog, EnvLogMessage)
|
||||
viper.SetDefault(EnvDummyPath, DummyPath)
|
||||
viper.SetDefault(EnvLogMessage, EnvDefaultLogMessage)
|
||||
|
||||
exePath := viper.GetString(EnvDummyPath)
|
||||
|
||||
logPath := viper.GetString(EnvLog)
|
||||
logMessage := viper.GetString(EnvLogMessage)
|
||||
if logPath != "" {
|
||||
var (
|
||||
err error
|
||||
file *os.File
|
||||
)
|
||||
|
||||
if file, err = os.OpenFile(logPath, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0o666); err == nil {
|
||||
defer func() {
|
||||
_ = file.Close()
|
||||
}()
|
||||
|
||||
if err = wingmate.NewLog(file); err == nil {
|
||||
wingmate.Log().Info().Msg(logMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StartRandomInstances(exePath)
|
||||
}
|
||||
|
||||
func StartRandomInstances(exePath string) {
|
||||
num := (rand.Uint32() % 16) + 16
|
||||
|
||||
var (
|
||||
ctr uint32
|
||||
cmd *exec.Cmd
|
||||
err error
|
||||
)
|
||||
for ctr = 0; ctr < num; ctr++ {
|
||||
cmd = exec.Command(exePath)
|
||||
if err = cmd.Start(); err != nil {
|
||||
log.Printf("failed to run %s: %+v\n", exePath, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
40
cmd/experiment/spawner/spawner.go
Normal file
40
cmd/experiment/spawner/spawner.go
Normal file
@ -0,0 +1,40 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os/exec"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
const (
|
||||
EnvPrefix = "WINGMATE"
|
||||
EnvOneShotPath = "ONESHOT_PATH"
|
||||
OneShotPath = "/usr/local/bin/wmoneshot"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
cmd *exec.Cmd
|
||||
err error
|
||||
t *time.Ticker
|
||||
)
|
||||
viper.SetEnvPrefix(EnvPrefix)
|
||||
viper.BindEnv(EnvOneShotPath)
|
||||
viper.SetDefault(EnvOneShotPath, OneShotPath)
|
||||
|
||||
exePath := viper.GetString(EnvOneShotPath)
|
||||
|
||||
t = time.NewTicker(time.Second * 5)
|
||||
for {
|
||||
cmd = exec.Command(exePath)
|
||||
if err = cmd.Run(); err != nil {
|
||||
log.Printf("failed to run %s: %+v\n", exePath, err)
|
||||
} else {
|
||||
log.Printf("%s executed\n", exePath)
|
||||
}
|
||||
|
||||
<-t.C
|
||||
}
|
||||
}
|
||||
@ -6,21 +6,32 @@ import (
|
||||
"log"
|
||||
"os/exec"
|
||||
"sync"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
const (
|
||||
// DummyPath = "/workspaces/wingmate/cmd/experiment/dummy/dummy"
|
||||
DummyPath = "/usr/local/bin/wmdummy"
|
||||
DummyPath = "/usr/local/bin/wmdummy"
|
||||
EnvDummyPath = "DUMMY_PATH"
|
||||
EnvPrefix = "WINGMATE"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
stdout io.ReadCloser
|
||||
stderr io.ReadCloser
|
||||
wg *sync.WaitGroup
|
||||
err error
|
||||
stdout io.ReadCloser
|
||||
stderr io.ReadCloser
|
||||
wg *sync.WaitGroup
|
||||
err error
|
||||
exePath string
|
||||
)
|
||||
cmd := exec.Command(DummyPath)
|
||||
viper.SetEnvPrefix(EnvPrefix)
|
||||
viper.BindEnv(EnvDummyPath)
|
||||
viper.SetDefault(EnvDummyPath, DummyPath)
|
||||
|
||||
exePath = viper.GetString(EnvDummyPath)
|
||||
|
||||
cmd := exec.Command(exePath)
|
||||
|
||||
if stdout, err = cmd.StdoutPipe(); err != nil {
|
||||
log.Panic(err)
|
||||
|
||||
@ -89,27 +89,27 @@ func readCrontab(path string) ([]*Cron, error) {
|
||||
hasRun: false,
|
||||
}
|
||||
if err = c.setField(minute, parts[1]); err != nil {
|
||||
wingmate.Log().Error().Msgf("error parsing minute field %#v", err)
|
||||
wingmate.Log().Error().Msgf("error parsing minute field %+v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if err = c.setField(hour, parts[2]); err != nil {
|
||||
wingmate.Log().Error().Msgf("error parsing hour field %#v", err)
|
||||
wingmate.Log().Error().Msgf("error parsing hour field %+v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if err = c.setField(dom, parts[3]); err != nil {
|
||||
wingmate.Log().Error().Msgf("error parsing day of month field %#v", err)
|
||||
wingmate.Log().Error().Msgf("error parsing day of month field %+v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if err = c.setField(month, parts[4]); err != nil {
|
||||
wingmate.Log().Error().Msgf("error parsing month field %#v", err)
|
||||
wingmate.Log().Error().Msgf("error parsing month field %+v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if err = c.setField(dow, parts[5]); err != nil {
|
||||
wingmate.Log().Error().Msgf("error parsing day of week field %#v", err)
|
||||
wingmate.Log().Error().Msgf("error parsing day of week field %+v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
@ -201,12 +201,12 @@ func (c *Cron) setField(field cronField, input string) error {
|
||||
*cField = &specAny{}
|
||||
} else if strings.HasPrefix(input, "*/") {
|
||||
if parsed64, err = strconv.ParseUint(input[2:], 10, 8); err != nil {
|
||||
return fmt.Errorf("error parse field %#v with input %s: %w", field, input, err)
|
||||
return fmt.Errorf("error parse field %+v with input %s: %w", field, input, err)
|
||||
}
|
||||
|
||||
parsed = uint8(parsed64)
|
||||
if fr.valid(parsed) {
|
||||
return fmt.Errorf("error parse field %#v with input %s: invalid value", field, input)
|
||||
if !fr.valid(parsed) {
|
||||
return fmt.Errorf("error parse field %+v with input %s parsed to %d: invalid value", field, input, parsed)
|
||||
}
|
||||
multi = make([]uint8, 0)
|
||||
current = parsed
|
||||
@ -224,12 +224,12 @@ func (c *Cron) setField(field cronField, input string) error {
|
||||
multi = make([]uint8, 0)
|
||||
for _, s := range multiStr {
|
||||
if parsed64, err = strconv.ParseUint(s, 10, 8); err != nil {
|
||||
return fmt.Errorf("error parse field %#v with input %s: %w", field, input, err)
|
||||
return fmt.Errorf("error parse field %+v with input %s: %w", field, input, err)
|
||||
}
|
||||
|
||||
parsed = uint8(parsed64)
|
||||
if fr.valid(parsed) {
|
||||
return fmt.Errorf("error parse field %#v with input %s: invalid value", field, input)
|
||||
if !fr.valid(parsed) {
|
||||
return fmt.Errorf("error parse field %+v with input %s: invalid value", field, input)
|
||||
}
|
||||
|
||||
multi = append(multi, parsed)
|
||||
@ -240,12 +240,12 @@ func (c *Cron) setField(field cronField, input string) error {
|
||||
}
|
||||
} else {
|
||||
if parsed64, err = strconv.ParseUint(input, 10, 8); err != nil {
|
||||
return fmt.Errorf("error parse field %#v with input %s: %w", field, input, err)
|
||||
return fmt.Errorf("error parse field %+v with input %s: %w", field, input, err)
|
||||
}
|
||||
|
||||
parsed = uint8(parsed64)
|
||||
if fr.valid(parsed) {
|
||||
return fmt.Errorf("error parse field %#v with input %s: invalid value", field, input)
|
||||
if !fr.valid(parsed) {
|
||||
return fmt.Errorf("error parse field %+v with input %s: invalid value", field, input)
|
||||
}
|
||||
|
||||
*cField = &specExact{
|
||||
|
||||
@ -10,6 +10,11 @@ RUN go build -v
|
||||
WORKDIR /root/wingmate/cmd/experiment/starter
|
||||
RUN go build -v
|
||||
|
||||
WORKDIR /root/wingmate/cmd/experiment/spawner
|
||||
RUN go build -v
|
||||
|
||||
WORKDIR /root/wingmate/cmd/experiment/oneshot
|
||||
RUN go build -v
|
||||
|
||||
|
||||
|
||||
@ -19,6 +24,8 @@ RUN apk add tzdata && ln -s /usr/share/zoneinfo/Australia/Sydney /etc/localtime
|
||||
COPY --from=builder /root/wingmate/cmd/wingmate/wingmate /usr/local/bin/wingmate
|
||||
COPY --from=builder /root/wingmate/cmd/experiment/dummy/dummy /usr/local/bin/wmdummy
|
||||
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
|
||||
ADD --chmod=755 docker/alpine/entry.sh /usr/local/bin/entry.sh
|
||||
ADD --chmod=755 docker/alpine/etc /etc
|
||||
|
||||
|
||||
1
docker/alpine/etc/wingmate/crontab
Normal file
1
docker/alpine/etc/wingmate/crontab
Normal file
@ -0,0 +1 @@
|
||||
*/5 * * * * /etc/wingmate/crontab.d/cron1.sh
|
||||
6
docker/alpine/etc/wingmate/crontab.d/cron1.sh
Normal file
6
docker/alpine/etc/wingmate/crontab.d/cron1.sh
Normal file
@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
export WINGMATE_DUMMY_PATH=/usr/local/bin/wmdummy
|
||||
export WINGMATE_LOG=/var/log/cron1.log
|
||||
export WINGMATE_LOG_MESSAGE="cron executed in minute 5,10,15,20,25,30,35,40,45,50,55"
|
||||
exec /usr/local/bin/wmoneshot
|
||||
5
docker/alpine/etc/wingmate/service/spawner.sh
Normal file
5
docker/alpine/etc/wingmate/service/spawner.sh
Normal file
@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
export WINGMATE_ONESHOT_PATH=/usr/local/bin/wmoneshot
|
||||
export WINGMATE_DUMMY_PATH=/usr/local/bin/wmdummy
|
||||
exec /usr/local/bin/wmspawner
|
||||
46
init/cron.go
46
init/cron.go
@ -1,6 +1,7 @@
|
||||
package init
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os/exec"
|
||||
"sync"
|
||||
"time"
|
||||
@ -8,19 +9,60 @@ import (
|
||||
"gitea.suyono.dev/suyono/wingmate"
|
||||
)
|
||||
|
||||
const (
|
||||
cronTag = "cron"
|
||||
)
|
||||
|
||||
func (i *Init) cron(wg *sync.WaitGroup, cron Cron, exitFlag <-chan any) {
|
||||
defer wg.Done()
|
||||
|
||||
var (
|
||||
iwg *sync.WaitGroup
|
||||
err error
|
||||
stdout io.ReadCloser
|
||||
stderr io.ReadCloser
|
||||
)
|
||||
|
||||
ticker := time.NewTicker(time.Second * 20)
|
||||
cron:
|
||||
for {
|
||||
if cron.TimeToRun(time.Now()) {
|
||||
cmd := exec.Command(cron.Command().Path())
|
||||
if err := cmd.Run(); err != nil {
|
||||
wingmate.Log().Error().Msgf("running cron %s error %#v", cron.Command().Path(), err)
|
||||
iwg = &sync.WaitGroup{}
|
||||
|
||||
if stdout, err = cmd.StdoutPipe(); err != nil {
|
||||
wingmate.Log().Error().Str(cronTag, cron.Command().Path()).Msgf("stdout pipe: %+v", err)
|
||||
goto fail
|
||||
}
|
||||
|
||||
if stderr, err = cmd.StderrPipe(); err != nil {
|
||||
wingmate.Log().Error().Str(cronTag, cron.Command().Path()).Msgf("stderr pipe: %+v", err)
|
||||
_ = stdout.Close()
|
||||
goto fail
|
||||
}
|
||||
|
||||
iwg.Add(1)
|
||||
go i.pipeReader(iwg, stdout, cronTag, cron.Command().Path())
|
||||
|
||||
iwg.Add(1)
|
||||
go i.pipeReader(iwg, stderr, cronTag, cron.Command().Path())
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
wingmate.Log().Error().Msgf("starting cron %s error %+v", cron.Command().Path(), err)
|
||||
_ = stdout.Close()
|
||||
_ = stderr.Close()
|
||||
iwg.Wait()
|
||||
goto fail
|
||||
}
|
||||
|
||||
iwg.Wait()
|
||||
|
||||
if err = cmd.Wait(); err != nil {
|
||||
wingmate.Log().Error().Str(cronTag, cron.Command().Path()).Msgf("got error when waiting: %+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
fail:
|
||||
select {
|
||||
case <-exitFlag:
|
||||
ticker.Stop()
|
||||
|
||||
@ -29,9 +29,9 @@ func (i *Init) service(wg *sync.WaitGroup, path Path, exitFlag <-chan any) {
|
||||
wingmate.Log().Info().Str(serviceTag, path.Path()).Msg("stopped")
|
||||
}()
|
||||
|
||||
failStatus = false
|
||||
service:
|
||||
for {
|
||||
failStatus = false
|
||||
cmd := exec.Command(path.Path())
|
||||
iwg = &sync.WaitGroup{}
|
||||
|
||||
@ -41,7 +41,7 @@ service:
|
||||
goto fail
|
||||
}
|
||||
iwg.Add(1)
|
||||
go i.pipeReader(iwg, stdout, path.Path())
|
||||
go i.pipeReader(iwg, stdout, serviceTag, path.Path())
|
||||
|
||||
if stderr, err = cmd.StderrPipe(); err != nil {
|
||||
wingmate.Log().Error().Str(serviceTag, path.Path()).Msgf("stderr pipe: %#v", err)
|
||||
@ -50,11 +50,14 @@ service:
|
||||
goto fail
|
||||
}
|
||||
iwg.Add(1)
|
||||
go i.pipeReader(iwg, stderr, path.Path())
|
||||
go i.pipeReader(iwg, stderr, serviceTag, path.Path())
|
||||
|
||||
if err = cmd.Start(); err != nil {
|
||||
wingmate.Log().Error().Msgf("starting service %s error %#v", path.Path(), err)
|
||||
failStatus = true
|
||||
_ = stdout.Close()
|
||||
_ = stderr.Close()
|
||||
iwg.Wait()
|
||||
goto fail
|
||||
}
|
||||
|
||||
@ -77,17 +80,17 @@ service:
|
||||
|
||||
}
|
||||
|
||||
func (i *Init) pipeReader(wg *sync.WaitGroup, pipe io.ReadCloser, serviceName string) {
|
||||
func (i *Init) pipeReader(wg *sync.WaitGroup, pipe io.ReadCloser, tag, serviceName string) {
|
||||
defer wg.Done()
|
||||
|
||||
scanner := bufio.NewScanner(pipe)
|
||||
for scanner.Scan() {
|
||||
wingmate.Log().Info().Str(serviceTag, serviceName).Msg(scanner.Text())
|
||||
wingmate.Log().Info().Str(tag, serviceName).Msg(scanner.Text())
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
wingmate.Log().Error().Str(serviceTag, serviceName).Msgf("got error when reading pipe: %#v", err)
|
||||
wingmate.Log().Error().Str(tag, serviceName).Msgf("got error when reading pipe: %#v", err)
|
||||
}
|
||||
|
||||
wingmate.Log().Info().Str(serviceTag, serviceName).Msg("closing pipe")
|
||||
wingmate.Log().Info().Str(tag, serviceName).Msg("closing pipe")
|
||||
}
|
||||
|
||||
@ -27,11 +27,13 @@ func (i *Init) waiter(wg *sync.WaitGroup, runningFlag <-chan any, sigHandlerFlag
|
||||
flagged = true
|
||||
wait:
|
||||
for {
|
||||
select {
|
||||
case <-runningFlag:
|
||||
wingmate.Log().Info().Msg("waiter received shutdown signal...")
|
||||
running = false
|
||||
default:
|
||||
if running {
|
||||
select {
|
||||
case <-runningFlag:
|
||||
wingmate.Log().Info().Msg("waiter received shutdown signal...")
|
||||
running = false
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
if _, err = unix.Wait4(-1, &ws, 0, nil); err != nil {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user