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
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
package system
|
||||
|
||||
var Version = "1.11.13"
|
||||
var Version = "develop"
|
||||
|
|
Loading…
Reference in New Issue
Block a user