Compare commits
	
		
			12 Commits
		
	
	
		
			release/v1
			...
			develop
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | d739948989 | ||
|  | ac260bd5ee | ||
|  | 2f4a0d7262 | ||
|  | 1d8b383682 | ||
|  | 934bf2493d | ||
|  | 29e4425e21 | ||
|  | 5a15612754 | ||
|  | ad1ae862a9 | ||
|  | 3114a3b82e | ||
|  | 500f217514 | ||
|  | 9ffbcdcdb1 | ||
|  | 9b341db2db | 
							
								
								
									
										6
									
								
								.github/workflows/push.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.github/workflows/push.yaml
									
									
									
									
										vendored
									
									
								
							|  | @ -16,7 +16,7 @@ jobs: | |||
|       fail-fast: false | ||||
|       matrix: | ||||
|         os: [ubuntu-22.04] | ||||
|         go: ["1.21.9", "1.22.2"] | ||||
|         go: ["1.22.5"] | ||||
|         goos: [linux] | ||||
|         goarch: [amd64, arm64] | ||||
| 
 | ||||
|  | @ -62,14 +62,14 @@ jobs: | |||
| 
 | ||||
|       - name: Upload Release Artifact | ||||
|         uses: actions/upload-artifact@v4 | ||||
|         if: ${{ (github.ref == 'refs/heads/develop' || github.event_name == 'pull_request') && matrix.go == '1.21.8' }} | ||||
|         if: ${{ (github.ref == 'refs/heads/develop' || github.event_name == 'pull_request') && matrix.go == '1.22.5' }} | ||||
|         with: | ||||
|           name: wings_linux_${{ matrix.goarch }} | ||||
|           path: dist/wings | ||||
| 
 | ||||
|       - name: Upload Debug Artifact | ||||
|         uses: actions/upload-artifact@v4 | ||||
|         if: ${{ (github.ref == 'refs/heads/develop' || github.event_name == 'pull_request') && matrix.go == '1.21.8' }} | ||||
|         if: ${{ (github.ref == 'refs/heads/develop' || github.event_name == 'pull_request') && matrix.go == '1.22.5' }} | ||||
|         with: | ||||
|           name: wings_linux_${{ matrix.goarch }}_debug | ||||
|           path: dist/wings_debug | ||||
|  |  | |||
							
								
								
									
										2
									
								
								.github/workflows/release.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/release.yaml
									
									
									
									
										vendored
									
									
								
							|  | @ -17,7 +17,7 @@ jobs: | |||
|       - name: Setup Go | ||||
|         uses: actions/setup-go@v5 | ||||
|         with: | ||||
|           go-version: "1.21.9" | ||||
|           go-version: "1.22.5" | ||||
| 
 | ||||
|       - name: Build release binaries | ||||
|         env: | ||||
|  |  | |||
							
								
								
									
										10
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								CHANGELOG.md
									
									
									
									
									
								
							|  | @ -1,5 +1,15 @@ | |||
| # Changelog | ||||
| 
 | ||||
| ## v1.11.14 | ||||
| 
 | ||||
| ### Added | ||||
| 
 | ||||
| * Support relative file paths for the Wings config ([#180](https://github.com/pterodactyl/wings/pull/180)) | ||||
| 
 | ||||
| ### Fixed | ||||
| 
 | ||||
| * Folders not being sorted before files properly ([#5078](https://github.com/pterodactyl/panel/issues/5078) | ||||
| 
 | ||||
| ## v1.11.13 | ||||
| 
 | ||||
| ### Fixed | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| # Stage 1 (Build) | ||||
| FROM golang:1.21.9-alpine AS builder | ||||
| FROM golang:1.22.5-alpine AS builder | ||||
| 
 | ||||
| ARG VERSION | ||||
| RUN apk add --update --no-cache git make | ||||
|  |  | |||
							
								
								
									
										15
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								README.md
									
									
									
									
									
								
							|  | @ -19,13 +19,14 @@ I would like to extend my sincere thanks to the following sponsors for helping f | |||
| [Interested in becoming a sponsor?](https://github.com/sponsors/matthewpi) | ||||
| 
 | ||||
| | Company                                                      | About                                                                                                                                                                                                                                           | | ||||
| |--------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | ||||
| | [**Aussie Server Hosts**](https://aussieserverhosts.com/)    | No frills Australian Owned and operated High Performance Server hosting for some of the most demanding games serving Australia and New Zealand.                                                                                                 | | ||||
| | [**BisectHosting**](https://www.bisecthosting.com/)          | BisectHosting provides Minecraft, Valheim and other server hosting services with the highest reliability and lightning fast support since 2012.                                                                                                 | | ||||
| | [**MineStrator**](https://minestrator.com/)                  | Looking for the most highend French hosting company for your minecraft server? More than 24,000 members on our discord trust us. Give us a try!                                                                                                 | | ||||
| | [**HostEZ**](https://hostez.io)                              | US & EU Rust & Minecraft Hosting. DDoS Protected bare metal, VPS and colocation with low latency, high uptime and maximum availability. EZ!                                                                                                     | | ||||
| | [**Blueprint**](https://blueprint.zip/?pterodactyl=true)     | Create and install Pterodactyl addons and themes with the growing Blueprint framework - the package-manager for Pterodactyl. Use multiple modifications at once without worrying about conflicts and make use of the large extension ecosystem. | | ||||
| | [**indifferent broccoli**](https://indifferentbroccoli.com/) | indifferent broccoli is a game server hosting and rental company. With us, you get top-notch computer power for your gaming sessions. We destroy lag, latency, and complexity--letting you focus on the fun stuff.                              | | ||||
| |--------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | ||||
| | [**Aussie Server Hosts**](https://aussieserverhosts.com/)    | No frills Australian Owned and operated High Performance Server hosting for some of the most demanding games serving Australia and New Zealand.                                                                                                                       | | ||||
| | [**CodeNode LLC**](https://codenode.gg/)                     | Looking for simplicity? Well, look no further! CodeNode has got you covered with everything you need at the rock-bottom price of $1.75 per GB, including dedicated IPs in Dallas, Texas, and Amsterdam, Netherlands. We're not just good, we're the best in the game! | | ||||
| | [**BisectHosting**](https://www.bisecthosting.com/)          | BisectHosting provides Minecraft, Valheim and other server hosting services with the highest reliability and lightning fast support since 2012.                                                                                                                       | | ||||
| | [**MineStrator**](https://minestrator.com/)                  | Looking for the most highend French hosting company for your minecraft server? More than 24,000 members on our discord trust us. Give us a try!                                                                                                                       | | ||||
| | [**HostEZ**](https://hostez.io)                              | US & EU Rust & Minecraft Hosting. DDoS Protected bare metal, VPS and colocation with low latency, high uptime and maximum availability. EZ!                                                                                                                           | | ||||
| | [**Blueprint**](https://blueprint.zip/?pterodactyl=true)     | Create and install Pterodactyl addons and themes with the growing Blueprint framework - the package-manager for Pterodactyl. Use multiple modifications at once without worrying about conflicts and make use of the large extension ecosystem.                       | | ||||
| | [**indifferent broccoli**](https://indifferentbroccoli.com/) | indifferent broccoli is a game server hosting and rental company. With us, you get top-notch computer power for your gaming sessions. We destroy lag, latency, and complexity--letting you focus on the fun stuff.                                                    | | ||||
| 
 | ||||
| ## Documentation | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										19
									
								
								cmd/root.go
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								cmd/root.go
									
									
									
									
									
								
							|  | @ -13,7 +13,6 @@ import ( | |||
| 	"path/filepath" | ||||
| 	"runtime" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/NYTimes/logrotate" | ||||
|  | @ -113,6 +112,9 @@ func rootCmdRun(cmd *cobra.Command, _ []string) { | |||
| 	if err := config.EnsurePterodactylUser(); err != nil { | ||||
| 		log.WithField("error", err).Fatal("failed to create pterodactyl system user") | ||||
| 	} | ||||
| 	if err := config.ConfigurePasswd(); err != nil { | ||||
| 		log.WithField("error", err).Fatal("failed to configure container passwd file") | ||||
| 	} | ||||
| 	log.WithFields(log.Fields{ | ||||
| 		"username": config.Get().System.Username, | ||||
| 		"uid":      config.Get().System.User.Uid, | ||||
|  | @ -379,13 +381,14 @@ func rootCmdRun(cmd *cobra.Command, _ []string) { | |||
| // Reads the configuration from the disk and then sets up the global singleton
 | ||||
| // with all the configuration values.
 | ||||
| func initConfig() { | ||||
| 	if !strings.HasPrefix(configPath, "/") { | ||||
| 		d, err := os.Getwd() | ||||
| 	if !filepath.IsAbs(configPath) { | ||||
| 		d, err := filepath.Abs(configPath) | ||||
| 		if err != nil { | ||||
| 			log2.Fatalf("cmd/root: could not determine directory: %s", err) | ||||
| 			log2.Fatalf("cmd/root: failed to get path to config file: %s", err) | ||||
| 		} | ||||
| 		configPath = path.Clean(path.Join(d, configPath)) | ||||
| 		configPath = d | ||||
| 	} | ||||
| 
 | ||||
| 	err := config.FromFile(configPath) | ||||
| 	if err != nil { | ||||
| 		if errors.Is(err, os.ErrNotExist) { | ||||
|  | @ -440,18 +443,18 @@ in all copies or substantial portions of the Software.%s`), system.Version, time | |||
| } | ||||
| 
 | ||||
| func exitWithConfigurationNotice() { | ||||
| 	fmt.Print(colorstring.Color(` | ||||
| 	fmt.Printf(colorstring.Color(` | ||||
| [_red_][white][bold]Error: Configuration File Not Found[reset] | ||||
| 
 | ||||
| Wings was not able to locate your configuration file, and therefore is not | ||||
| able to complete its boot process. Please ensure you have copied your instance | ||||
| configuration file into the default location below. | ||||
| 
 | ||||
| Default Location: /etc/pterodactyl/config.yml | ||||
| Default Location: %s | ||||
| 
 | ||||
| [yellow]This is not a bug with this software. Please do not make a bug report | ||||
| for this issue, it will be closed.[reset] | ||||
| 
 | ||||
| `)) | ||||
| `), config.DefaultLocation) | ||||
| 	os.Exit(1) | ||||
| } | ||||
|  |  | |||
|  | @ -172,6 +172,25 @@ type SystemConfiguration struct { | |||
| 		Gid int `yaml:"gid"` | ||||
| 	} `yaml:"user"` | ||||
| 
 | ||||
| 	// Passwd controls the mounting of a generated passwd files into containers started by Wings.
 | ||||
| 	Passwd struct { | ||||
| 		// Enable controls whether generated passwd files should be mounted into containers.
 | ||||
| 		//
 | ||||
| 		// By default this option is disabled and Wings will not mount any additional passwd
 | ||||
| 		// files into containers.
 | ||||
| 		Enable bool `yaml:"enabled" default:"false"` | ||||
| 
 | ||||
| 		// Directory is the directory on disk where the generated files will be stored.
 | ||||
| 		// This directory may be temporary as it will be re-created whenever Wings is started.
 | ||||
| 		//
 | ||||
| 		// This path **WILL** be both written to by Wings and mounted into containers created by
 | ||||
| 		// Wings. If you are running Wings itself in a container, this path will need to be mounted
 | ||||
| 		// into the Wings container as the exact path on the host, which should match the value
 | ||||
| 		// specified here. If you are using SELinux, you will need to make sure this file has the
 | ||||
| 		// correct SELinux context in order for containers to use it.
 | ||||
| 		Directory string `yaml:"directory" default:"/run/wings/etc"` | ||||
| 	} `yaml:"passwd"` | ||||
| 
 | ||||
| 	// The amount of time in seconds that can elapse before a server's disk space calculation is
 | ||||
| 	// considered stale and a re-check should occur. DANGER: setting this value too low can seriously
 | ||||
| 	// impact system performance and cause massive I/O bottlenecks and high CPU usage for the Wings
 | ||||
|  | @ -497,6 +516,37 @@ func EnsurePterodactylUser() error { | |||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // ConfigurePasswd generates required passwd files for use with containers started by Wings.
 | ||||
| func ConfigurePasswd() error { | ||||
| 	passwd := _config.System.Passwd | ||||
| 	if !passwd.Enable { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	v := []byte(fmt.Sprintf( | ||||
| 		`root:x:0: | ||||
| container:x:%d: | ||||
| nogroup:x:65534:`, | ||||
| 		_config.System.User.Gid, | ||||
| 	)) | ||||
| 	if err := os.WriteFile(filepath.Join(passwd.Directory, "group"), v, 0o644); err != nil { | ||||
| 		return fmt.Errorf("failed to write file to %s/group: %v", passwd.Directory, err) | ||||
| 	} | ||||
| 
 | ||||
| 	v = []byte(fmt.Sprintf( | ||||
| 		`root:x:0:0::/root:/bin/sh | ||||
| container:x:%d:%d::/home/container:/bin/sh | ||||
| nobody:x:65534:65534::/var/empty:/bin/sh | ||||
| `, | ||||
| 		_config.System.User.Uid, | ||||
| 		_config.System.User.Gid, | ||||
| 	)) | ||||
| 	if err := os.WriteFile(filepath.Join(passwd.Directory, "passwd"), v, 0o644); err != nil { | ||||
| 		return fmt.Errorf("failed to write file to %s/passwd: %v", passwd.Directory, err) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // FromFile reads the configuration from the provided file and stores it in the
 | ||||
| // global singleton for this instance.
 | ||||
| func FromFile(path string) error { | ||||
|  | @ -561,6 +611,13 @@ func ConfigureDirectories() error { | |||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if _config.System.Passwd.Enable { | ||||
| 		log.WithField("path", _config.System.Passwd.Directory).Debug("ensuring passwd directory exists") | ||||
| 		if err := os.MkdirAll(_config.System.Passwd.Directory, 0o755); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -4,7 +4,6 @@ import ( | |||
| 	"context" | ||||
| 	"os" | ||||
| 	"strings" | ||||
| 	"syscall" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"emperror.dev/errors" | ||||
|  | @ -143,42 +142,49 @@ func (e *Environment) Stop(ctx context.Context) error { | |||
| 	s := e.meta.Stop | ||||
| 	e.mu.RUnlock() | ||||
| 
 | ||||
| 	// A native "stop" as the Type field value will just skip over all of this
 | ||||
| 	// logic and end up only executing the container stop command (which may or
 | ||||
| 	// may not work as expected).
 | ||||
| 	if s.Type == "" || s.Type == remote.ProcessStopSignal { | ||||
| 		if s.Type == "" { | ||||
| 			log.WithField("container_id", e.Id).Warn("no stop configuration detected for environment, using termination procedure") | ||||
| 		} | ||||
| 
 | ||||
| 		signal := os.Kill | ||||
| 		// Handle a few common cases, otherwise just fall through and just pass along
 | ||||
| 		// the os.Kill signal to the process.
 | ||||
| 		switch strings.ToUpper(s.Value) { | ||||
| 		case "SIGABRT": | ||||
| 			signal = syscall.SIGABRT | ||||
| 		case "SIGINT": | ||||
| 			signal = syscall.SIGINT | ||||
| 		case "SIGTERM": | ||||
| 			signal = syscall.SIGTERM | ||||
| 		} | ||||
| 		return e.Terminate(ctx, signal) | ||||
| 	} | ||||
| 
 | ||||
| 	// If the process is already offline don't switch it back to stopping. Just leave it how
 | ||||
| 	// it is and continue through to the stop handling for the process.
 | ||||
| 	if e.st.Load() != environment.ProcessOfflineState { | ||||
| 		e.SetState(environment.ProcessStoppingState) | ||||
| 	} | ||||
| 
 | ||||
| 	// Handle signal based actions
 | ||||
| 	if s.Type == remote.ProcessStopSignal { | ||||
| 		log.WithField("signal_value", s.Value).Debug("stopping server using signal") | ||||
| 
 | ||||
| 		// Handle some common signals - Default to SIGKILL
 | ||||
| 		signal := "SIGKILL" | ||||
| 		switch strings.ToUpper(s.Value) { | ||||
| 		case "SIGABRT": | ||||
| 			signal = "SIGABRT" | ||||
| 		case "SIGINT", "C": | ||||
| 			signal = "SIGINT" | ||||
| 		case "SIGTERM": | ||||
| 			signal = "SIGTERM" | ||||
| 		case "SIGKILL": | ||||
| 			signal = "SIGKILL" | ||||
| 		default: | ||||
| 			log.Info("Unrecognised signal requested, defaulting to SIGKILL") | ||||
| 		} | ||||
| 
 | ||||
| 		return e.SignalContainer(ctx, signal) | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	// Handle command based stops
 | ||||
| 	// Only attempt to send the stop command to the instance if we are actually attached to
 | ||||
| 	// the instance. If we are not for some reason, just send the container stop event.
 | ||||
| 	if e.IsAttached() && s.Type == remote.ProcessStopCommand { | ||||
| 		return e.SendCommand(s.Value) | ||||
| 	} | ||||
| 
 | ||||
| 	// Allow the stop action to run for however long it takes, similar to executing a command
 | ||||
| 	// and using a different logic pathway to wait for the container to stop successfully.
 | ||||
| 	if s.Type == "" { | ||||
| 		log.WithField("container_id", e.Id).Warn("no stop configuration detected for environment, using native docker stop") | ||||
| 	} | ||||
| 
 | ||||
| 	// Fallback to a native docker stop. As we aren't passing a signal to ContainerStop docker will
 | ||||
| 	// attempt to stop the container using the default stop signal, SIGTERM, unless
 | ||||
| 	// another signal was specified in the Dockerfile
 | ||||
| 	//
 | ||||
| 	// Using a negative timeout here will allow the container to stop gracefully,
 | ||||
| 	// rather than forcefully terminating it.  Value is in seconds, but -1 is
 | ||||
|  | @ -224,7 +230,7 @@ func (e *Environment) WaitForStop(ctx context.Context, duration time.Duration, t | |||
| 
 | ||||
| 	doTermination := func(s string) error { | ||||
| 		e.log().WithField("step", s).WithField("duration", duration).Warn("container stop did not complete in time, terminating process...") | ||||
| 		return e.Terminate(ctx, os.Kill) | ||||
| 		return e.Terminate(ctx, "SIGKILL") | ||||
| 	} | ||||
| 
 | ||||
| 	// We pass through the timed context for this stop action so that if one of the
 | ||||
|  | @ -268,8 +274,8 @@ func (e *Environment) WaitForStop(ctx context.Context, duration time.Duration, t | |||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Terminate forcefully terminates the container using the signal provided.
 | ||||
| func (e *Environment) Terminate(ctx context.Context, signal os.Signal) error { | ||||
| // Sends the specified signal to the container in an attempt to stop it.
 | ||||
| func (e *Environment) SignalContainer(ctx context.Context, signal string) error { | ||||
| 	c, err := e.ContainerInspect(ctx) | ||||
| 	if err != nil { | ||||
| 		// Treat missing containers as an okay error state, means it is obviously
 | ||||
|  | @ -294,11 +300,27 @@ func (e *Environment) Terminate(ctx context.Context, signal os.Signal) error { | |||
| 
 | ||||
| 	// We set it to stopping than offline to prevent crash detection from being triggered.
 | ||||
| 	e.SetState(environment.ProcessStoppingState) | ||||
| 	sig := strings.TrimSuffix(strings.TrimPrefix(signal.String(), "signal "), "ed") | ||||
| 	if err := e.client.ContainerKill(ctx, e.Id, sig); err != nil && !client.IsErrNotFound(err) { | ||||
| 	if err := e.client.ContainerKill(ctx, e.Id, signal); err != nil && !client.IsErrNotFound(err) { | ||||
| 		return errors.WithStack(err) | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| // Terminate forcefully terminates the container using the signal provided.
 | ||||
| // then sets its state to stopped.
 | ||||
| func (e *Environment) Terminate(ctx context.Context, signal string) error { | ||||
| 
 | ||||
| 	// Send the signal to the container to kill it
 | ||||
| 	if err := e.SignalContainer(ctx, signal); err != nil { | ||||
| 		return errors.WithStack(err) | ||||
| 	} | ||||
| 
 | ||||
| 	// We expect Terminate to instantly kill the container
 | ||||
| 	// so go ahead and mark it as dead and clean up
 | ||||
| 	e.SetState(environment.ProcessOfflineState) | ||||
| 
 | ||||
| 	return nil | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -2,7 +2,6 @@ package environment | |||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"os" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/pterodactyl/wings/events" | ||||
|  | @ -72,7 +71,7 @@ type ProcessEnvironment interface { | |||
| 
 | ||||
| 	// Terminate stops a running server instance using the provided signal. This function
 | ||||
| 	// is a no-op if the server is already stopped.
 | ||||
| 	Terminate(ctx context.Context, signal os.Signal) error | ||||
| 	Terminate(ctx context.Context, signal string) error | ||||
| 
 | ||||
| 	// Destroys the environment removing any containers that were created (in Docker
 | ||||
| 	// environments at least).
 | ||||
|  |  | |||
|  | @ -34,7 +34,7 @@ type Mount struct { | |||
| // Limits is the build settings for a given server that impact docker container
 | ||||
| // creation and resource limits for a server instance.
 | ||||
| type Limits struct { | ||||
| 	// The total amount of memory in megabytes that this server is allowed to
 | ||||
| 	// The total amount of memory in mebibytes that this server is allowed to
 | ||||
| 	// use on the host system.
 | ||||
| 	MemoryLimit int64 `json:"memory_limit"` | ||||
| 
 | ||||
|  | @ -79,7 +79,7 @@ func (l Limits) MemoryOverheadMultiplier() float64 { | |||
| } | ||||
| 
 | ||||
| func (l Limits) BoundedMemoryLimit() int64 { | ||||
| 	return int64(math.Round(float64(l.MemoryLimit) * l.MemoryOverheadMultiplier() * 1_000_000)) | ||||
| 	return int64(math.Round(float64(l.MemoryLimit) * l.MemoryOverheadMultiplier() * 1024 * 1024)) | ||||
| } | ||||
| 
 | ||||
| // ConvertedSwap returns the amount of swap available as a total in bytes. This
 | ||||
|  | @ -90,7 +90,7 @@ func (l Limits) ConvertedSwap() int64 { | |||
| 		return -1 | ||||
| 	} | ||||
| 
 | ||||
| 	return (l.Swap * 1_000_000) + l.BoundedMemoryLimit() | ||||
| 	return (l.Swap * 1024 * 1024) + l.BoundedMemoryLimit() | ||||
| } | ||||
| 
 | ||||
| // ProcessLimit returns the process limit for a container. This is currently
 | ||||
|  | @ -105,7 +105,7 @@ func (l Limits) AsContainerResources() container.Resources { | |||
| 	pids := l.ProcessLimit() | ||||
| 	resources := container.Resources{ | ||||
| 		Memory:            l.BoundedMemoryLimit(), | ||||
| 		MemoryReservation: l.MemoryLimit * 1_000_000, | ||||
| 		MemoryReservation: l.MemoryLimit * 1024 * 1024, | ||||
| 		MemorySwap:        l.ConvertedSwap(), | ||||
| 		BlkioWeight:       l.IoWeight, | ||||
| 		OomKillDisable:    &l.OOMDisabled, | ||||
|  |  | |||
							
								
								
									
										36
									
								
								flake.lock
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								flake.lock
									
									
									
									
									
								
							|  | @ -5,11 +5,11 @@ | |||
|         "nixpkgs-lib": "nixpkgs-lib" | ||||
|       }, | ||||
|       "locked": { | ||||
|         "lastModified": 1706830856, | ||||
|         "narHash": "sha256-a0NYyp+h9hlb7ddVz4LUn1vT/PLwqfrWYcHMvFB1xYg=", | ||||
|         "lastModified": 1719994518, | ||||
|         "narHash": "sha256-pQMhCCHyQGRzdfAkdJ4cIWiw+JNuWsTX7f0ZYSyz0VY=", | ||||
|         "owner": "hercules-ci", | ||||
|         "repo": "flake-parts", | ||||
|         "rev": "b253292d9c0a5ead9bc98c4e9a26c6312e27d69f", | ||||
|         "rev": "9227223f6d922fee3c7b190b2cc238a99527bbb7", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
|  | @ -20,11 +20,11 @@ | |||
|     }, | ||||
|     "nixpkgs": { | ||||
|       "locked": { | ||||
|         "lastModified": 1707956935, | ||||
|         "narHash": "sha256-ZL2TrjVsiFNKOYwYQozpbvQSwvtV/3Me7Zwhmdsfyu4=", | ||||
|         "lastModified": 1721562059, | ||||
|         "narHash": "sha256-Tybxt65eyOARf285hMHIJ2uul8SULjFZbT9ZaEeUnP8=", | ||||
|         "owner": "NixOS", | ||||
|         "repo": "nixpkgs", | ||||
|         "rev": "a4d4fe8c5002202493e87ec8dbc91335ff55552c", | ||||
|         "rev": "68c9ed8bbed9dfce253cc91560bf9043297ef2fe", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
|  | @ -36,20 +36,14 @@ | |||
|     }, | ||||
|     "nixpkgs-lib": { | ||||
|       "locked": { | ||||
|         "dir": "lib", | ||||
|         "lastModified": 1706550542, | ||||
|         "narHash": "sha256-UcsnCG6wx++23yeER4Hg18CXWbgNpqNXcHIo5/1Y+hc=", | ||||
|         "owner": "NixOS", | ||||
|         "repo": "nixpkgs", | ||||
|         "rev": "97b17f32362e475016f942bbdfda4a4a72a8a652", | ||||
|         "type": "github" | ||||
|         "lastModified": 1719876945, | ||||
|         "narHash": "sha256-Fm2rDDs86sHy0/1jxTOKB1118Q0O3Uc7EC0iXvXKpbI=", | ||||
|         "type": "tarball", | ||||
|         "url": "https://github.com/NixOS/nixpkgs/archive/5daf0514482af3f97abaefc78a6606365c9108e2.tar.gz" | ||||
|       }, | ||||
|       "original": { | ||||
|         "dir": "lib", | ||||
|         "owner": "NixOS", | ||||
|         "ref": "nixos-unstable", | ||||
|         "repo": "nixpkgs", | ||||
|         "type": "github" | ||||
|         "type": "tarball", | ||||
|         "url": "https://github.com/NixOS/nixpkgs/archive/5daf0514482af3f97abaefc78a6606365c9108e2.tar.gz" | ||||
|       } | ||||
|     }, | ||||
|     "root": { | ||||
|  | @ -66,11 +60,11 @@ | |||
|         ] | ||||
|       }, | ||||
|       "locked": { | ||||
|         "lastModified": 1707300477, | ||||
|         "narHash": "sha256-qQF0fEkHlnxHcrKIMRzOETnRBksUK048MXkX0SOmxvA=", | ||||
|         "lastModified": 1721769617, | ||||
|         "narHash": "sha256-6Pqa0bi5nV74IZcENKYRToRNM5obo1EQ+3ihtunJ014=", | ||||
|         "owner": "numtide", | ||||
|         "repo": "treefmt-nix", | ||||
|         "rev": "ac599dab59a66304eb511af07b3883114f061b9d", | ||||
|         "rev": "8db8970be1fb8be9c845af7ebec53b699fe7e009", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
|  |  | |||
|  | @ -1,6 +1,8 @@ | |||
| package filesystem | ||||
| 
 | ||||
| import ( | ||||
| 	"golang.org/x/sys/unix" | ||||
| 	"slices" | ||||
| 	"sync" | ||||
| 	"sync/atomic" | ||||
| 	"time" | ||||
|  | @ -164,6 +166,8 @@ func (fs *Filesystem) DirectorySize(root string) (int64, error) { | |||
| 		return 0, err | ||||
| 	} | ||||
| 
 | ||||
| 	var hardLinks []uint64 | ||||
| 
 | ||||
| 	var size atomic.Int64 | ||||
| 	err = fs.unixFS.WalkDirat(dirfd, name, func(dirfd int, name, _ string, d ufs.DirEntry, err error) error { | ||||
| 		if err != nil { | ||||
|  | @ -180,8 +184,16 @@ func (fs *Filesystem) DirectorySize(root string) (int64, error) { | |||
| 			return errors.Wrap(err, "lstatat err") | ||||
| 		} | ||||
| 
 | ||||
| 		// TODO: detect if info is a hard-link and de-duplicate it.
 | ||||
| 		// ref; https://github.com/pterodactyl/wings/pull/181/files
 | ||||
| 		var sysFileInfo = info.Sys().(*unix.Stat_t) | ||||
| 		if sysFileInfo.Nlink > 1 { | ||||
| 			// Hard links have the same inode number
 | ||||
| 			if slices.Contains(hardLinks, sysFileInfo.Ino) { | ||||
| 				// Don't add hard links size twice
 | ||||
| 				return nil | ||||
| 			} else { | ||||
| 				hardLinks = append(hardLinks, sysFileInfo.Ino) | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		size.Add(info.Size()) | ||||
| 		return nil | ||||
|  |  | |||
|  | @ -480,9 +480,9 @@ func (fs *Filesystem) ListDirectory(p string) ([]Stat, error) { | |||
| 		case a.IsDir() && b.IsDir(): | ||||
| 			return 0 | ||||
| 		case a.IsDir(): | ||||
| 			return 1 | ||||
| 		default: | ||||
| 			return -1 | ||||
| 		default: | ||||
| 			return 1 | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
|  |  | |||
|  | @ -29,6 +29,21 @@ func (s *Server) Mounts() []environment.Mount { | |||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	// Handle mounting a generated `/etc/passwd` if the feature is enabled.
 | ||||
| 	if passwd := config.Get().System.Passwd; passwd.Enable { | ||||
| 		s.Log().WithFields(log.Fields{"source_path": passwd.Directory}).Info("mouting generated /etc/{group,passwd} to workaround UID/GID issues") | ||||
| 		m = append(m, environment.Mount{ | ||||
| 			Source:   filepath.Join(passwd.Directory, "group"), | ||||
| 			Target:   "/etc/group", | ||||
| 			ReadOnly: true, | ||||
| 		}) | ||||
| 		m = append(m, environment.Mount{ | ||||
| 			Source:   filepath.Join(passwd.Directory, "passwd"), | ||||
| 			Target:   "/etc/passwd", | ||||
| 			ReadOnly: true, | ||||
| 		}) | ||||
| 	} | ||||
| 
 | ||||
| 	// Also include any of this server's custom mounts when returning them.
 | ||||
| 	return append(m, s.customMounts()...) | ||||
| } | ||||
|  | @ -56,14 +71,12 @@ func (s *Server) customMounts() []environment.Mount { | |||
| 			if !strings.HasPrefix(source, filepath.Clean(allowed)) { | ||||
| 				continue | ||||
| 			} | ||||
| 
 | ||||
| 			mounted = true | ||||
| 			mounts = append(mounts, environment.Mount{ | ||||
| 				Source:   source, | ||||
| 				Target:   target, | ||||
| 				ReadOnly: m.ReadOnly, | ||||
| 			}) | ||||
| 
 | ||||
| 			break | ||||
| 		} | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,7 +3,6 @@ package server | |||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"emperror.dev/errors" | ||||
|  | @ -161,7 +160,7 @@ func (s *Server) HandlePowerAction(action PowerAction, waitSeconds ...int) error | |||
| 
 | ||||
| 		return s.Environment.Start(s.Context()) | ||||
| 	case PowerActionTerminate: | ||||
| 		return s.Environment.Terminate(s.Context(), os.Kill) | ||||
| 		return s.Environment.Terminate(s.Context(), "SIGKILL") | ||||
| 	} | ||||
| 
 | ||||
| 	return errors.New("attempting to handle unknown power action") | ||||
|  |  | |||
|  | @ -28,6 +28,7 @@ func (s *Server) SyncWithEnvironment() { | |||
| 		Mounts:      s.Mounts(), | ||||
| 		Allocations: cfg.Allocations, | ||||
| 		Limits:      cfg.Build, | ||||
| 		Labels:      cfg.Labels, | ||||
| 	}) | ||||
| 
 | ||||
| 	// For Docker specific environments we also want to update the configured image
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user