Skip to content

Commit

Permalink
update process managers
Browse files Browse the repository at this point in the history
  • Loading branch information
et-nik committed Feb 29, 2024
1 parent 487ae90 commit be9f8bf
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 29 deletions.
3 changes: 3 additions & 0 deletions internal/app/contracts/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ type Executor interface {
}

type ProcessManager interface {
Install(ctx context.Context, server *domain.Server, out io.Writer) (domain.Result, error)
Uninstall(ctx context.Context, server *domain.Server, out io.Writer) (domain.Result, error)

Start(ctx context.Context, server *domain.Server, out io.Writer) (domain.Result, error)
Stop(ctx context.Context, server *domain.Server, out io.Writer) (domain.Result, error)
Restart(ctx context.Context, server *domain.Server, out io.Writer) (domain.Result, error)
Expand Down
7 changes: 7 additions & 0 deletions internal/app/game_server_commands/delete_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ func (cmd *defaultDeleteServer) Execute(ctx context.Context, server *domain.Serv
cmd.SetComplete()
}()

_, err := cmd.processManager.Uninstall(ctx, server, cmd.output)
if err != nil {
cmd.SetResult(ErrorResult)
_, _ = cmd.output.Write([]byte(err.Error()))
return errors.WithMessage(err, "failed to execute process manager uninstall")
}

if cmd.cfg.Scripts.Delete != "" {
return cmd.removeByScript(ctx, server)
}
Expand Down
6 changes: 6 additions & 0 deletions internal/app/game_server_commands/install_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,12 @@ func (cmd *installServer) Execute(ctx context.Context, server *domain.Server) er
return errors.WithMessage(err, "[game_server_commands.installServer] failed to install game server")
}

_, err = cmd.processManager.Install(ctx, server, cmd.installOutput)
if err != nil {
cmd.SetResult(ErrorResult)
return errors.WithMessage(err, "failed to execute process manager install")
}

return cmd.startServerIfNeeded(ctx, server)
}

Expand Down
10 changes: 10 additions & 0 deletions internal/processmanager/simple.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ func NewSimple(cfg *config.Config, executor, detailedExecutor contracts.Executor
}
}

func (pm *Simple) Install(_ context.Context, _ *domain.Server, _ io.Writer) (domain.Result, error) {
// Nothing to do here
return domain.SuccessResult, nil
}

func (pm *Simple) Uninstall(_ context.Context, _ *domain.Server, _ io.Writer) (domain.Result, error) {
// Nothing to do here
return domain.SuccessResult, nil
}

func (pm *Simple) Start(
ctx context.Context, server *domain.Server, out io.Writer,
) (domain.Result, error) {
Expand Down
14 changes: 14 additions & 0 deletions internal/processmanager/systemd.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,20 @@ func NewSystemD(cfg *config.Config, _, detailedExecutor contracts.Executor) *Sys
}
}

func (pm *SystemD) Install(
_ context.Context, _ *domain.Server, _ io.Writer,
) (domain.Result, error) {
// Nothing to do here
return domain.SuccessResult, nil
}

func (pm *SystemD) Uninstall(
_ context.Context, _ *domain.Server, _ io.Writer,
) (domain.Result, error) {
// Nothing to do here
return domain.SuccessResult, nil
}

func (pm *SystemD) Start(ctx context.Context, server *domain.Server, out io.Writer) (domain.Result, error) {
f, err := os.Create(pm.logFile(server))
if err != nil {
Expand Down
10 changes: 10 additions & 0 deletions internal/processmanager/tmux.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ func NewTmux(cfg *config.Config, executor, detailedExecutor contracts.Executor)
}
}

func (pm *Tmux) Install(_ context.Context, _ *domain.Server, _ io.Writer) (domain.Result, error) {
// Nothing to do here
return domain.SuccessResult, nil
}

func (pm *Tmux) Uninstall(_ context.Context, _ *domain.Server, _ io.Writer) (domain.Result, error) {
// Nothing to do here
return domain.SuccessResult, nil
}

func (pm *Tmux) Start(
ctx context.Context, server *domain.Server, out io.Writer,
) (domain.Result, error) {
Expand Down
113 changes: 84 additions & 29 deletions internal/processmanager/winsw.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ const (
outputSizeLimit = 30000

errorCodeCannotStart = 1053

commandInstall = "install"
commandRefresh = "refresh"
commandUninstall = "uninstall"
commandStart = "start"
commandStop = "stop"
commandRestart = "restart"
commandStatus = "status"
)

type WinSW struct {
Expand All @@ -44,17 +52,34 @@ func NewWinSW(cfg *config.Config, _, detailedExecutor contracts.Executor) *WinSW
}
}

func (pm *WinSW) Start(ctx context.Context, server *domain.Server, out io.Writer) (domain.Result, error) {
return pm.command(ctx, server, "start", out)
}

func (pm *WinSW) Stop(ctx context.Context, server *domain.Server, out io.Writer) (domain.Result, error) {
_, err := pm.runWinSWCommand(ctx, "stop", server, out)
func (pm *WinSW) Install(ctx context.Context, server *domain.Server, out io.Writer) (domain.Result, error) {
createdNewService, err := pm.makeService(ctx, server)
if err != nil {
return domain.ErrorResult, errors.WithMessage(err, "failed to run stop command")
return domain.ErrorResult, errors.WithMessage(err, "failed to make service")
}

var result domain.Result

if createdNewService {
result, err = pm.runWinSWCommand(ctx, commandInstall, server, out)
if err != nil {
return domain.ErrorResult, errors.WithMessage(err, "failed to install service")
}
if result != domain.SuccessResult {
return domain.ErrorResult, errors.New("failed to install service")
}
} else {
result, err = pm.runWinSWCommand(ctx, commandRefresh, server, out)
if err != nil {
return domain.ErrorResult, errors.WithMessage(err, "failed to refresh service")
}
}

_, err = pm.runWinSWCommand(ctx, "uninstall", server, out)
return domain.SuccessResult, nil
}

func (pm *WinSW) Uninstall(ctx context.Context, server *domain.Server, out io.Writer) (domain.Result, error) {
_, err := pm.runWinSWCommand(ctx, commandUninstall, server, out)
if err != nil {
return domain.ErrorResult, errors.WithMessage(err, "failed to run uninstall command")
}
Expand All @@ -67,8 +92,21 @@ func (pm *WinSW) Stop(ctx context.Context, server *domain.Server, out io.Writer)
return domain.SuccessResult, nil
}

func (pm *WinSW) Start(ctx context.Context, server *domain.Server, out io.Writer) (domain.Result, error) {
return pm.command(ctx, server, commandStart, out)
}

func (pm *WinSW) Stop(ctx context.Context, server *domain.Server, out io.Writer) (domain.Result, error) {
_, err := pm.runWinSWCommand(ctx, commandStop, server, out)
if err != nil {
return domain.ErrorResult, errors.WithMessage(err, "failed to run stop command")
}

return domain.SuccessResult, nil
}

func (pm *WinSW) Restart(ctx context.Context, server *domain.Server, out io.Writer) (domain.Result, error) {
return pm.command(ctx, server, "restart", out)
return pm.command(ctx, server, commandRestart, out)
}

const (
Expand All @@ -82,7 +120,7 @@ func (pm *WinSW) Status(ctx context.Context, server *domain.Server, out io.Write
return domain.ErrorResult, nil
}

result, err := pm.runWinSWCommand(ctx, "status", server, out)
result, err := pm.runWinSWCommand(ctx, commandStatus, server, out)
if err != nil {
return domain.ErrorResult, errors.Wrap(err, "failed to get daemon status")
}
Expand Down Expand Up @@ -129,22 +167,22 @@ func (pm *WinSW) command(
var result domain.Result

if createdNewService {
result, err = pm.runWinSWCommand(ctx, "install", server, out)
result, err = pm.runWinSWCommand(ctx, commandInstall, server, out)
if err != nil {
return domain.ErrorResult, errors.WithMessage(err, "failed to install service")
}
if result != domain.SuccessResult {
return domain.ErrorResult, errors.New("failed to install service")
}
} else {
result, err = pm.runWinSWCommand(ctx, "refresh", server, out)
result, err = pm.runWinSWCommand(ctx, commandRefresh, server, out)
if err != nil {
return domain.ErrorResult, errors.WithMessage(err, "failed to refresh service")
}
if result != domain.SuccessResult {
logger.Warn(ctx, "failed to refresh service config, trying to install service")

result, err = pm.runWinSWCommand(ctx, "install", server, out)
result, err = pm.runWinSWCommand(ctx, commandInstall, server, out)
if err != nil {
return domain.ErrorResult, errors.WithMessage(err, "failed to install service")
}
Expand All @@ -159,7 +197,7 @@ func (pm *WinSW) command(
return domain.ErrorResult, errors.WithMessage(err, "failed to exec command")
}

if result == errorCodeCannotStart && command == "start" {
if result == errorCodeCannotStart && command == commandStart {
_, err = pm.tryFixReinstallService(ctx, server, out)
if err != nil {
return domain.ErrorResult, errors.WithMessage(err, "failed to try fix by reinstalling service")
Expand Down Expand Up @@ -216,12 +254,12 @@ func (pm *WinSW) SendInput(
func (pm *WinSW) tryFixReinstallService(
ctx context.Context, server *domain.Server, out io.Writer,
) (domain.Result, error) {
result, err := pm.runWinSWCommand(ctx, "uninstall", server, out)
result, err := pm.runWinSWCommand(ctx, commandUninstall, server, out)
if err != nil {
logger.Warn(ctx, errors.WithMessage(err, "failed to uninstall service"))
}

result, err = pm.runWinSWCommand(ctx, "install", server, out)
result, err = pm.runWinSWCommand(ctx, commandInstall, server, out)
if err != nil {
logger.Warn(ctx, errors.WithMessage(err, "failed to install service"))
}
Expand Down Expand Up @@ -256,13 +294,35 @@ func (pm *WinSW) makeService(ctx context.Context, server *domain.Server) (bool,
}
}

createdNew := false
serviceFileNotExist := false

_, err := os.Stat(serviceFile)
if err != nil && !errors.Is(err, os.ErrNotExist) {
return false, errors.WithMessage(err, "failed to check file")
}
if err != nil && errors.Is(err, os.ErrNotExist) {
serviceFileNotExist = true
}

serviceConfig, err := pm.buildServiceConfig(server)
if err != nil {
return false, errors.WithMessage(err, "failed to build service config")
}

// If service file exists, check if it's the same
if !serviceFileNotExist {
oldServiceConfig, err := os.ReadFile(serviceFile)
if err != nil {
return false, errors.WithMessage(err, "failed to read file")
}

if string(oldServiceConfig) == serviceConfig {
return false, nil
}
}

flag := os.O_TRUNC | os.O_WRONLY
if _, err := os.Stat(serviceFile); errors.Is(err, os.ErrNotExist) {
// It means that service file does not exist.
// We will create new service.
// If file exists, we will update it.
createdNew = true
if serviceFileNotExist {
flag = os.O_CREATE | os.O_WRONLY
}

Expand All @@ -277,17 +337,12 @@ func (pm *WinSW) makeService(ctx context.Context, server *domain.Server) (bool,
}
}()

c, err := pm.buildServiceConfig(server)
if err != nil {
return false, errors.WithMessage(err, "failed to build service config")
}

_, err = f.WriteString(c)
_, err = f.WriteString(serviceConfig)
if err != nil {
return false, errors.WithMessage(err, "failed to write to file")
}

return createdNew, nil
return serviceFileNotExist, nil
}

func (pm *WinSW) buildServiceConfig(server *domain.Server) (string, error) {
Expand Down

0 comments on commit be9f8bf

Please sign in to comment.