Code cleanup; use a worker pool for updating file permissions to avoid run-away go-routines
Co-Authored-By: Jakob <schrej@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									38efb68e8a
								
							
						
					
					
						commit
						5e8425ad6a
					
				| 
						 | 
				
			
			@ -1,12 +1,13 @@
 | 
			
		|||
package config
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/apex/log"
 | 
			
		||||
	"github.com/cobaugh/osrelease"
 | 
			
		||||
	"github.com/creasty/defaults"
 | 
			
		||||
	"github.com/gammazero/workerpool"
 | 
			
		||||
	"github.com/gbrlsnchs/jwt/v3"
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
	"gopkg.in/yaml.v2"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
| 
						 | 
				
			
			@ -14,6 +15,7 @@ import (
 | 
			
		|||
	"os/user"
 | 
			
		||||
	"path"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
| 
						 | 
				
			
			@ -154,7 +156,7 @@ func ReadConfiguration(path string) (*Configuration, error) {
 | 
			
		|||
	return c, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var Mutex sync.RWMutex
 | 
			
		||||
var mu sync.RWMutex
 | 
			
		||||
 | 
			
		||||
var _config *Configuration
 | 
			
		||||
var _jwtAlgo *jwt.HMACSHA
 | 
			
		||||
| 
						 | 
				
			
			@ -164,14 +166,14 @@ var _debugViaFlag bool
 | 
			
		|||
// anything trying to set a different configuration value, or read the configuration
 | 
			
		||||
// will be paused until it is complete.
 | 
			
		||||
func Set(c *Configuration) {
 | 
			
		||||
	Mutex.Lock()
 | 
			
		||||
	mu.Lock()
 | 
			
		||||
 | 
			
		||||
	if _config == nil || _config.AuthenticationToken != c.AuthenticationToken {
 | 
			
		||||
		_jwtAlgo = jwt.NewHS256([]byte(c.AuthenticationToken))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_config = c
 | 
			
		||||
	Mutex.Unlock()
 | 
			
		||||
	mu.Unlock()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SetDebugViaFlag(d bool) {
 | 
			
		||||
| 
						 | 
				
			
			@ -181,16 +183,16 @@ func SetDebugViaFlag(d bool) {
 | 
			
		|||
// Get the global configuration instance. This is a read-safe operation that will block
 | 
			
		||||
// if the configuration is presently being modified.
 | 
			
		||||
func Get() *Configuration {
 | 
			
		||||
	Mutex.RLock()
 | 
			
		||||
	defer Mutex.RUnlock()
 | 
			
		||||
	mu.RLock()
 | 
			
		||||
	defer mu.RUnlock()
 | 
			
		||||
 | 
			
		||||
	return _config
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns the in-memory JWT algorithm.
 | 
			
		||||
func GetJwtAlgorithm() *jwt.HMACSHA {
 | 
			
		||||
	Mutex.RLock()
 | 
			
		||||
	defer Mutex.RUnlock()
 | 
			
		||||
	mu.RLock()
 | 
			
		||||
	defer mu.RUnlock()
 | 
			
		||||
 | 
			
		||||
	return _jwtAlgo
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -199,7 +201,7 @@ func GetJwtAlgorithm() *jwt.HMACSHA {
 | 
			
		|||
func NewFromPath(path string) (*Configuration, error) {
 | 
			
		||||
	c := new(Configuration)
 | 
			
		||||
	if err := defaults.Set(c); err != nil {
 | 
			
		||||
		return c, err
 | 
			
		||||
		return c, errors.WithStack(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.unsafeSetPath(path)
 | 
			
		||||
| 
						 | 
				
			
			@ -237,12 +239,12 @@ func (c *Configuration) EnsurePterodactylUser() (*user.User, error) {
 | 
			
		|||
	if err == nil {
 | 
			
		||||
		return u, c.setSystemUser(u)
 | 
			
		||||
	} else if _, ok := err.(user.UnknownUserError); !ok {
 | 
			
		||||
		return nil, err
 | 
			
		||||
		return nil, errors.WithStack(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sysName, err := getSystemName()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
		return nil, errors.WithStack(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var command = fmt.Sprintf("useradd --system --no-create-home --shell /bin/false %s", c.System.Username)
 | 
			
		||||
| 
						 | 
				
			
			@ -255,17 +257,17 @@ func (c *Configuration) EnsurePterodactylUser() (*user.User, error) {
 | 
			
		|||
		// We have to create the group first on Alpine, so do that here before continuing on
 | 
			
		||||
		// to the user creation process.
 | 
			
		||||
		if _, err := exec.Command("addgroup", "-S", c.System.Username).Output(); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
			return nil, errors.WithStack(err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	split := strings.Split(command, " ")
 | 
			
		||||
	if _, err := exec.Command(split[0], split[1:]...).Output(); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
		return nil, errors.WithStack(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if u, err := user.Lookup(c.System.Username); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
		return nil, errors.WithStack(err)
 | 
			
		||||
	} else {
 | 
			
		||||
		return u, c.setSystemUser(u)
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -286,6 +288,8 @@ func (c *Configuration) setSystemUser(u *user.User) error {
 | 
			
		|||
	return c.WriteToDisk()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var uuid4Regex = regexp.MustCompile("^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$")
 | 
			
		||||
 | 
			
		||||
// Ensures that the configured data directory has the correct permissions assigned to
 | 
			
		||||
// all of the files and folders within.
 | 
			
		||||
func (c *Configuration) EnsureFilePermissions() error {
 | 
			
		||||
| 
						 | 
				
			
			@ -295,45 +299,27 @@ func (c *Configuration) EnsureFilePermissions() error {
 | 
			
		|||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r := regexp.MustCompile("^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$")
 | 
			
		||||
 | 
			
		||||
	files, err := ioutil.ReadDir(c.System.Data)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
		return errors.WithStack(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	su, err := user.Lookup(c.System.Username)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wg := new(sync.WaitGroup)
 | 
			
		||||
	pool := workerpool.New(runtime.GOMAXPROCS(0))
 | 
			
		||||
 | 
			
		||||
	for _, file := range files {
 | 
			
		||||
		wg.Add(1)
 | 
			
		||||
		f := file
 | 
			
		||||
		if !f.IsDir() || !uuid4Regex.MatchString(f.Name()) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Asynchronously run through the list of files and folders in the data directory. If
 | 
			
		||||
		// the item is not a folder, or is not a folder that matches the expected UUIDv4 format
 | 
			
		||||
		// skip over it.
 | 
			
		||||
		//
 | 
			
		||||
		// If we do have a positive match, run a chown against the directory.
 | 
			
		||||
		go func(f os.FileInfo) {
 | 
			
		||||
			defer wg.Done()
 | 
			
		||||
 | 
			
		||||
			if !f.IsDir() || !r.MatchString(f.Name()) {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			uid, _ := strconv.Atoi(su.Uid)
 | 
			
		||||
			gid, _ := strconv.Atoi(su.Gid)
 | 
			
		||||
 | 
			
		||||
			if err := os.Chown(path.Join(c.System.Data, f.Name()), uid, gid); err != nil {
 | 
			
		||||
		pool.Submit(func() {
 | 
			
		||||
			if err := os.Chown(path.Join(c.System.Data, f.Name()), c.System.User.Uid, c.System.User.Gid); err != nil {
 | 
			
		||||
				log.WithField("error", err).WithField("directory", f.Name()).Warn("failed to chown server directory")
 | 
			
		||||
			}
 | 
			
		||||
		}(file)
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wg.Wait()
 | 
			
		||||
	pool.StopWait()
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -359,11 +345,11 @@ func (c *Configuration) WriteToDisk() error {
 | 
			
		|||
 | 
			
		||||
	b, err := yaml.Marshal(&ccopy)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
		return errors.WithStack(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := ioutil.WriteFile(c.GetPath(), b, 0644); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
		return errors.WithStack(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
| 
						 | 
				
			
			@ -373,7 +359,7 @@ func (c *Configuration) WriteToDisk() error {
 | 
			
		|||
func getSystemName() (string, error) {
 | 
			
		||||
	// use osrelease to get release version and ID
 | 
			
		||||
	if release, err := osrelease.Read(); err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
		return "", errors.WithStack(err)
 | 
			
		||||
	} else {
 | 
			
		||||
		return release["ID"], nil
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user