Skip to content

Commit

Permalink
Server state handling; auto start servers if they were running when t…
Browse files Browse the repository at this point in the history
…he daemon stopped
  • Loading branch information
DaneEveritt committed Nov 25, 2019
1 parent 47c7c87 commit 85762ba
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 15 deletions.
3 changes: 1 addition & 2 deletions server/server.go
Expand Up @@ -29,7 +29,7 @@ type Server struct {
Suspended bool `json:"suspended"`

// The power state of the server.
State string `json:"state" yaml:"-"`
State string `default:"offline" json:"state"`

// The command that should be used when booting up the server instance.
Invocation string `json:"invocation"`
Expand Down Expand Up @@ -224,7 +224,6 @@ func FromConfiguration(data []byte, cfg *config.SystemConfiguration) (*Server, e
return nil, err
}

s.State = ProcessOfflineState
s.Environment = env
s.Cache = cache.New(time.Minute*10, time.Minute*15)
s.Filesystem = &Filesystem{
Expand Down
68 changes: 55 additions & 13 deletions wings.go
Expand Up @@ -5,8 +5,10 @@ import (
"flag"
"fmt"
"github.com/gorilla/websocket"
"github.com/pkg/errors"
"github.com/pterodactyl/wings/config"
"github.com/pterodactyl/wings/server"
"github.com/remeh/sizedwaitgroup"
"go.uber.org/zap"
"net/http"
)
Expand Down Expand Up @@ -68,26 +70,66 @@ func main() {
return
}

// Just for some nice log output.
for _, s := range servers {
zap.S().Infow("loaded configuration for server", zap.String("server", s.Uuid))
zap.S().Infow("ensuring envrionment exists", zap.String("server", s.Uuid))
}

if err := s.Environment.Create(); err != nil {
zap.S().Errorw("failed to create an environment for server", zap.String("server", s.Uuid), zap.Error(err))
}
// Create a new WaitGroup that limits us to 4 servers being bootstrapped at a time
// on Wings. This allows us to ensure the environment exists, write configurations,
// and reboot processes without causing a slow-down due to sequential booting.
wg := sizedwaitgroup.New(4)

if r, err := s.Environment.IsRunning(); err != nil {
zap.S().Errorw("error checking server environment status", zap.String("server", s.Uuid), zap.Error(err))
} else if r {
zap.S().Infow("detected server is running, re-attaching to process", zap.String("server", s.Uuid))
s.SetState(server.ProcessRunningState)
if err := s.Environment.Attach(); err != nil {
zap.S().Errorw("error attaching to server environment", zap.String("server", s.Uuid), zap.Error(err))
s.SetState(server.ProcessOfflineState)
for _, serv := range servers {
go func(s *server.Server) {
defer wg.Done()

// Create a server environment if none exists currently. This allows us to recover from Docker
// being reinstalled on the host system for example.
zap.S().Infow("ensuring envrionment exists", zap.String("server", s.Uuid))
if err := s.Environment.Create(); err != nil {
zap.S().Errorw("failed to create an environment for server", zap.String("server", s.Uuid), zap.Error(err))
}
}

if r, err := s.Environment.IsRunning(); err != nil {
zap.S().Errorw("error checking server environment status", zap.String("server", s.Uuid), zap.Error(err))
} else if r {
// If the server is currently running on Docker, mark the process as being in that state.
// We never want to stop an instance that is currently running external from Wings since
// that is a good way of keeping things running even if Wings gets in a very corrupted state.
zap.S().Infow("detected server is running, re-attaching to process", zap.String("server", s.Uuid))
s.SetState(server.ProcessRunningState)

// If we cannot attach to the environment go ahead and mark the processs as being offline.
if err := s.Environment.Attach(); err != nil {
zap.S().Warnw("error attaching to server environment", zap.String("server", s.Uuid), zap.Error(err))
s.SetState(server.ProcessOfflineState)
}
} else if !r {
// If the server is not in a running state right now but according to the configuration it
// should be, we want to go ahead and restart the instance.
if s.State == server.ProcessRunningState || s.State == server.ProcessStartingState {
if err := s.Environment.Start(); err != nil {
zap.S().Warnw(
"failed to put server instance back in running state",
zap.String("server", s.Uuid),
zap.Error(errors.WithStack(err)),
)
}
} else {
if s.State == "" {
// Addresses potentially invalid data in the stored file that can cause Wings to lose
// track of what the actual server state is.
s.SetState(server.ProcessOfflineState)
}
}
}
}(serv)
}

// Wait until all of the servers are ready to go before we fire up the HTTP server.
wg.Wait()

r := &Router{
Servers: servers,
token: c.AuthenticationToken,
Expand Down

2 comments on commit 85762ba

@schrej
Copy link
Member

@schrej schrej commented on 85762ba Nov 25, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you are missing a wg.Add() here.

@DaneEveritt
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, seems probable now that you mention it. I only have two servers currently so it boots fine, good catch.

Please sign in to comment.