attempt to update vhd on-the-fly
This is not currently working correctly — when setting the limit to 0 all existing files are destroyed. When setting it back to a non-zero value the old files are returned from the allocated disk. This at least starts getting the code pathways in place to handle it and introduces some additional lock safety on the VHD management code.
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
package filesystem
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/pterodactyl/wings/internal/vhd"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
@@ -35,14 +37,42 @@ func (ult *usageLookupTime) Get() time.Time {
|
||||
return ult.value
|
||||
}
|
||||
|
||||
// Returns the maximum amount of disk space that this Filesystem instance is allowed to use.
|
||||
// MaxDisk returns the maximum amount of disk space that this Filesystem
|
||||
// instance is allowed to use.
|
||||
func (fs *Filesystem) MaxDisk() int64 {
|
||||
return atomic.LoadInt64(&fs.diskLimit)
|
||||
}
|
||||
|
||||
// Sets the disk space limit for this Filesystem instance.
|
||||
func (fs *Filesystem) SetDiskLimit(i int64) {
|
||||
atomic.SwapInt64(&fs.diskLimit, i)
|
||||
// SetDiskLimit sets the disk space limit for this Filesystem instance. This
|
||||
// logic will also handle mounting or unmounting a virtual disk if it is being
|
||||
// used currently.
|
||||
func (fs *Filesystem) SetDiskLimit(ctx context.Context, i int64) error {
|
||||
// Do nothing if this method is called but the limit is not changing.
|
||||
if atomic.LoadInt64(&fs.diskLimit) == i {
|
||||
return nil
|
||||
}
|
||||
if vhd.Enabled() {
|
||||
if i == 0 && fs.IsVirtual() {
|
||||
fs.log().Debug("disk limit changed to 0, destroying virtual disk")
|
||||
// Remove the VHD if it is mounted so that we're just storing files directly on the system
|
||||
// since we cannot have a virtual disk with a space limit enforced like that.
|
||||
if err := fs.vhd.Destroy(ctx); err != nil {
|
||||
return errors.WithStackIf(err)
|
||||
}
|
||||
fs.vhd = nil
|
||||
}
|
||||
// If we're setting a disk size go ahead and mount the VHD if it isn't already mounted,
|
||||
// and then allocate the new space to the disk.
|
||||
if i > 0 {
|
||||
fs.log().Debug("disk limit updated, allocating new space to virtual disk")
|
||||
if err := fs.ConfigureDisk(ctx, i); err != nil {
|
||||
return errors.WithStackIf(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
fs.log().WithField("limit", i).Debug("disk limit updated")
|
||||
atomic.StoreInt64(&fs.diskLimit, i)
|
||||
return nil
|
||||
}
|
||||
|
||||
// HasSpaceErr is the same concept as HasSpaceAvailable however this will return
|
||||
@@ -76,8 +106,7 @@ func (fs *Filesystem) HasSpaceErr(allowStaleValue bool) error {
|
||||
func (fs *Filesystem) HasSpaceAvailable(allowStaleValue bool) bool {
|
||||
size, err := fs.DiskUsage(allowStaleValue)
|
||||
if err != nil {
|
||||
log.WithField("root", fs.root).WithField("error", err).
|
||||
Warn("failed to determine root fs directory size")
|
||||
fs.log().WithField("error", err).Warn("failed to determine root fs directory size")
|
||||
}
|
||||
return fs.MaxDisk() == 0 || size <= fs.MaxDisk()
|
||||
}
|
||||
@@ -125,8 +154,7 @@ func (fs *Filesystem) DiskUsage(allowStaleValue bool) (int64, error) {
|
||||
if !fs.lookupInProgress.Load() {
|
||||
go func(fs *Filesystem) {
|
||||
if _, err := fs.updateCachedDiskUsage(); err != nil {
|
||||
log.WithField("root", fs.root).WithField("error", err).
|
||||
Warn("failed to update fs disk usage from within routine")
|
||||
fs.log().WithField("error", err).Warn("failed to update fs disk usage from within routine")
|
||||
}
|
||||
}(fs)
|
||||
}
|
||||
@@ -249,3 +277,7 @@ func (fs *Filesystem) addDisk(i int64) int64 {
|
||||
|
||||
return atomic.AddInt64(&fs.diskUsed, i)
|
||||
}
|
||||
|
||||
func (fs *Filesystem) log() *log.Entry {
|
||||
return log.WithField("server", fs.uuid).WithField("root", fs.root)
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ type Filesystem struct {
|
||||
|
||||
// The root data directory path for this Filesystem instance.
|
||||
root string
|
||||
uuid string
|
||||
|
||||
isTest bool
|
||||
}
|
||||
@@ -46,6 +47,7 @@ type Filesystem struct {
|
||||
func New(uuid string, size int64, denylist []string) *Filesystem {
|
||||
root := filepath.Join(config.Get().System.Data, uuid)
|
||||
fs := Filesystem{
|
||||
uuid: uuid,
|
||||
root: root,
|
||||
diskLimit: size,
|
||||
diskCheckInterval: time.Duration(config.Get().System.DiskCheckInterval),
|
||||
|
||||
@@ -11,13 +11,29 @@ func (fs *Filesystem) IsVirtual() bool {
|
||||
return fs.vhd != nil
|
||||
}
|
||||
|
||||
// MountDisk will attempt to mount the underlying virtual disk for the server.
|
||||
// If the disk is already mounted this is a no-op function. If the filesystem is
|
||||
// not configured for virtual disks this function will panic.
|
||||
func (fs *Filesystem) MountDisk(ctx context.Context) error {
|
||||
if !fs.IsVirtual() {
|
||||
panic(errors.New("filesystem: cannot call MountDisk on Filesystem instance without VHD present"))
|
||||
// ConfigureDisk will attempt to create a new VHD if there is not one already
|
||||
// created for the filesystem. If there is this method will attempt to resize
|
||||
// the underlying data volume. Passing a size of 0 or less will panic.
|
||||
func (fs *Filesystem) ConfigureDisk(ctx context.Context, size int64) error {
|
||||
if size <= 0 {
|
||||
panic("filesystem: attempt to configure disk with empty size")
|
||||
}
|
||||
if fs.vhd == nil {
|
||||
fs.vhd = vhd.New(size, vhd.DiskPath(fs.uuid), fs.root)
|
||||
if err := fs.MountDisk(ctx); err != nil {
|
||||
return errors.WithStackIf(err)
|
||||
}
|
||||
}
|
||||
// Resize the disk now that it is for sure mounted and exists on the system.
|
||||
if err := fs.vhd.Resize(ctx, size); err != nil {
|
||||
return errors.WithStackIf(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MountDisk will attempt to mount the underlying virtual disk for the server.
|
||||
// If the disk is already mounted this is a no-op function.
|
||||
func (fs *Filesystem) MountDisk(ctx context.Context) error {
|
||||
err := fs.vhd.Mount(ctx)
|
||||
if errors.Is(err, vhd.ErrFilesystemMounted) {
|
||||
return nil
|
||||
|
||||
@@ -197,11 +197,11 @@ func (m *Manager) InitServer(ctx context.Context, data remote.ServerConfiguratio
|
||||
return nil, errors.WithStackIf(err)
|
||||
}
|
||||
|
||||
s.fs = filesystem.New(s.Id(), s.DiskSpace(), s.Config().Egg.FileDenylist)
|
||||
// If this is a virtuakl filesystem we need to go ahead and mount the disk
|
||||
s.fs = filesystem.New(s.ID(), s.DiskSpace(), s.Config().Egg.FileDenylist)
|
||||
// If this is a virtual filesystem we need to go ahead and mount the disk
|
||||
// so that everything is accessible.
|
||||
if s.fs.IsVirtual() && !m.skipVhdInitialization {
|
||||
log.WithField("server", s.Id()).Info("mounting virtual disk for server")
|
||||
log.WithField("server", s.ID()).Info("mounting virtual disk for server")
|
||||
if err := s.fs.MountDisk(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -179,6 +179,8 @@ func (s *Server) Log() *log.Entry {
|
||||
//
|
||||
// This also means mass actions can be performed against servers on the Panel
|
||||
// and they will automatically sync with Wings when the server is started.
|
||||
//
|
||||
// TODO: accept a context value rather than using the server's context.
|
||||
func (s *Server) Sync() error {
|
||||
cfg, err := s.client.GetServerConfiguration(s.Context(), s.ID())
|
||||
if err != nil {
|
||||
@@ -194,7 +196,9 @@ func (s *Server) Sync() error {
|
||||
|
||||
// Update the disk space limits for the server whenever the configuration for
|
||||
// it changes.
|
||||
s.fs.SetDiskLimit(s.DiskSpace())
|
||||
if err := s.fs.SetDiskLimit(s.Context(), s.DiskSpace()); err != nil {
|
||||
return errors.WrapIf(err, "server: failed to sync server configuration from API")
|
||||
}
|
||||
|
||||
s.SyncWithEnvironment()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user