diff --git a/cmd/root.go b/cmd/root.go index 25d9ff20..f411c53b 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -197,9 +197,9 @@ func rootCmdRun(cmd *cobra.Command, _ []string) { for _, serv := range manager.All() { s := serv - // For each server we encounter make sure the root data directory exists. - if err := s.EnsureDataDirectoryExists(); err != nil { - s.Log().Error("could not create root data directory for server: not loading server...") + // For each server ensure the minimal environment is configured for the server. + if err := s.CreateEnvironment(); err != nil { + s.Log().Error("could create base environment for server...") continue } diff --git a/config/config.go b/config/config.go index 37f0db82..a83936d8 100644 --- a/config/config.go +++ b/config/config.go @@ -177,11 +177,11 @@ type SystemConfiguration struct { 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. + // 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. + // Directory is the directory on disk where the generated passwd 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 @@ -192,6 +192,26 @@ type SystemConfiguration struct { Directory string `yaml:"directory" default:"/run/wings/etc"` } `yaml:"passwd"` + // MachineID controls the mounting of a generated `/etc/machine-id` file into containers started by Wings. + MachineID struct { + // Enable controls whether a generated machine-id file should be mounted + // into containers. + // + // By default this option is enabled and Wings will mount an additional + // machine-id file into containers. + Enable bool `yaml:"enabled" default:"true"` + + // Directory is the directory on disk where the generated machine-id 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/machine-id"` + } `yaml:"machine_id"` + // 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 @@ -634,6 +654,11 @@ func ConfigureDirectories() error { return err } + log.WithField("path", _config.System.TmpDirectory).Debug("ensuring temporary data directory exists") + if err := os.MkdirAll(_config.System.TmpDirectory, 0o700); err != nil { + return err + } + log.WithField("path", _config.System.ArchiveDirectory).Debug("ensuring archive data directory exists") if err := os.MkdirAll(_config.System.ArchiveDirectory, 0o700); err != nil { return err @@ -651,6 +676,13 @@ func ConfigureDirectories() error { } } + if _config.System.MachineID.Enable { + log.WithField("path", _config.System.MachineID.Directory).Debug("ensuring machine-id directory exists") + if err := os.MkdirAll(_config.System.MachineID.Directory, 0o755); err != nil { + return err + } + } + return nil } diff --git a/flake.lock b/flake.lock index bdf0fea9..e87c8a2f 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "nixpkgs-lib": "nixpkgs-lib" }, "locked": { - "lastModified": 1741352980, - "narHash": "sha256-+u2UunDA4Cl5Fci3m7S643HzKmIDAe+fiXrLqYsR2fs=", + "lastModified": 1768135262, + "narHash": "sha256-PVvu7OqHBGWN16zSi6tEmPwwHQ4rLPU9Plvs8/1TUBY=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "f4330d22f1c5d2ba72d3d22df5597d123fdb60a9", + "rev": "80daad04eddbbf5a4d883996a73f3f542fa437ac", "type": "github" }, "original": { @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1741379970, - "narHash": "sha256-Wh7esNh7G24qYleLvgOSY/7HlDUzWaL/n4qzlBePpiw=", + "lastModified": 1768127708, + "narHash": "sha256-1Sm77VfZh3mU0F5OqKABNLWxOuDeHIlcFjsXeeiPazs=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "36fd87baa9083f34f7f5027900b62ee6d09b1f2f", + "rev": "ffbc9f8cbaacfb331b6017d5a5abb21a492c9a38", "type": "github" }, "original": { @@ -36,11 +36,11 @@ }, "nixpkgs-lib": { "locked": { - "lastModified": 1740877520, - "narHash": "sha256-oiwv/ZK/2FhGxrCkQkB83i7GnWXPPLzoqFHpDD3uYpk=", + "lastModified": 1765674936, + "narHash": "sha256-k00uTP4JNfmejrCLJOwdObYC9jHRrr/5M/a/8L2EIdo=", "owner": "nix-community", "repo": "nixpkgs.lib", - "rev": "147dee35aab2193b174e4c0868bd80ead5ce755c", + "rev": "2075416fcb47225d9b68ac469a5c4801a9c4dd85", "type": "github" }, "original": { @@ -63,11 +63,11 @@ ] }, "locked": { - "lastModified": 1739829690, - "narHash": "sha256-mL1szCeIsjh6Khn3nH2cYtwO5YXG6gBiTw1A30iGeDU=", + "lastModified": 1768158989, + "narHash": "sha256-67vyT1+xClLldnumAzCTBvU0jLZ1YBcf4vANRWP3+Ak=", "owner": "numtide", "repo": "treefmt-nix", - "rev": "3d0579f5cc93436052d94b73925b48973a104204", + "rev": "e96d59dff5c0d7fddb9d113ba108f03c3ef99eca", "type": "github" }, "original": { diff --git a/server/mounts.go b/server/mounts.go index b2630287..51ef8d65 100644 --- a/server/mounts.go +++ b/server/mounts.go @@ -29,21 +29,34 @@ func (s *Server) Mounts() []environment.Mount { }, } + cfg := config.Get() + // 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") + if cfg.System.Passwd.Enable { + s.Log().WithFields(log.Fields{"source_path": cfg.System.Passwd.Directory}).Info("mouting generated /etc/{group,passwd} to workaround UID/GID issues") m = append(m, environment.Mount{ - Source: filepath.Join(passwd.Directory, "group"), + Source: filepath.Join(cfg.System.Passwd.Directory, "group"), Target: "/etc/group", ReadOnly: true, }) m = append(m, environment.Mount{ - Source: filepath.Join(passwd.Directory, "passwd"), + Source: filepath.Join(cfg.System.Passwd.Directory, "passwd"), Target: "/etc/passwd", ReadOnly: true, }) } + if cfg.System.MachineID.Enable { + // Hytale wants a machine-id in order to encrypt tokens for the server. + // So add a mount to `/etc/machine-id` to a source that contains the + // server's UUID without any dashes. + m = append(m, environment.Mount{ + Source: filepath.Join(cfg.System.MachineID.Directory, s.ID()), + Target: "/etc/machine-id", + ReadOnly: true, + }) + } + // Also include any of this server's custom mounts when returning them. return append(m, s.customMounts()...) } diff --git a/server/server.go b/server/server.go index e260cea6..a1777b04 100644 --- a/server/server.go +++ b/server/server.go @@ -1,11 +1,13 @@ package server import ( + "bytes" "context" "encoding/json" "fmt" "net/http" "os" + "path/filepath" "strings" "sync" @@ -259,6 +261,18 @@ func (s *Server) CreateEnvironment() error { return err } + cfg := config.Get() + if cfg.System.MachineID.Enable { + // Hytale wants a machine-id in order to encrypt tokens for the server. So + // write a machine-id file for the server that contains the server's UUID + // without any dashes. + p := filepath.Join(cfg.System.MachineID.Directory, s.ID()) + machineID := append(bytes.ReplaceAll([]byte(s.ID()), []byte{'-'}, []byte{}), '\n') + if err := os.WriteFile(p, machineID, 0o644); err != nil { + return fmt.Errorf("failed to write machine-id (at '%s') for server '%s': %w", p, s.ID(), err) + } + } + return s.Environment.Create() }