[#3896bk] Configure base support for properties file parsing
This commit is contained in:
parent
11c6738264
commit
1003abaa63
|
@ -3,8 +3,7 @@ package api
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/buger/jsonparser"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/pterodactyl/wings/parser"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
|
@ -14,44 +13,6 @@ const (
|
|||
ProcessStopNativeStop = "stop"
|
||||
)
|
||||
|
||||
// Defines a single find/replace instance for a given server configuration file.
|
||||
type ConfigurationFileReplacement struct {
|
||||
Match string `json:"match"`
|
||||
Value string `json:"value"`
|
||||
ValueType jsonparser.ValueType `json:"-"`
|
||||
}
|
||||
|
||||
func (cfr *ConfigurationFileReplacement) UnmarshalJSON(data []byte) error {
|
||||
if m, err := jsonparser.GetString(data, "match"); err != nil {
|
||||
return err
|
||||
} else {
|
||||
cfr.Match = m
|
||||
}
|
||||
|
||||
if v, dt, _, err := jsonparser.Get(data, "value"); err != nil {
|
||||
return err
|
||||
} else {
|
||||
if dt != jsonparser.String && dt != jsonparser.Number && dt != jsonparser.Boolean {
|
||||
return errors.New(
|
||||
fmt.Sprintf("cannot parse JSON: received unexpected replacement value type: %d", dt),
|
||||
)
|
||||
}
|
||||
|
||||
cfr.Value = string(v)
|
||||
cfr.ValueType = dt
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Defines a configuration file for the server startup. These will be looped over
|
||||
// and modified before the server finishes booting.
|
||||
type ConfigurationFile struct {
|
||||
FileName string `json:"file"`
|
||||
Parser string `json:"parser"`
|
||||
Replace []ConfigurationFileReplacement `json:"replace"`
|
||||
}
|
||||
|
||||
// Defines the process configuration for a given server instance. This sets what the
|
||||
// daemon is looking for to mark a server as done starting, what to do when stopping,
|
||||
// and what changes to make to the configuration file for a server.
|
||||
|
@ -64,7 +25,7 @@ type ServerConfiguration struct {
|
|||
Type string `json:"type"`
|
||||
Value string `json:"value"`
|
||||
} `json:"stop"`
|
||||
ConfigurationFiles []ConfigurationFile `json:"configs"`
|
||||
ConfigurationFiles []parser.ConfigurationFile `json:"configs"`
|
||||
}
|
||||
|
||||
// Fetches the server configuration and returns the struct for it.
|
||||
|
|
1
go.mod
1
go.mod
|
@ -23,6 +23,7 @@ require (
|
|||
github.com/imdario/mergo v0.3.8
|
||||
github.com/julienschmidt/httprouter v1.2.0
|
||||
github.com/kr/pretty v0.1.0 // indirect
|
||||
github.com/magiconair/properties v1.8.1
|
||||
github.com/mcuadros/go-defaults v1.1.0
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db
|
||||
github.com/olebedev/emitter v0.0.0-20190110104742-e8d1457e6aee
|
||||
|
|
2
go.sum
2
go.sum
|
@ -53,6 +53,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
|||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/magefile/mage v1.9.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
|
||||
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mcuadros/go-defaults v1.1.0 h1:K0LgSNfsSUrbEHR7HgfZpOHVWYsPnYh/dKTA7pGeZ/I=
|
||||
github.com/mcuadros/go-defaults v1.1.0/go.mod h1:vl9cJiNIIHISQeboDhZBUCiCOa3GkeioLe3Y95NXF6Y=
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
|
||||
|
|
98
parser/parser.go
Normal file
98
parser/parser.go
Normal file
|
@ -0,0 +1,98 @@
|
|||
package parser
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/buger/jsonparser"
|
||||
"github.com/magiconair/properties"
|
||||
"github.com/pkg/errors"
|
||||
"go.uber.org/zap"
|
||||
"os"
|
||||
)
|
||||
|
||||
type ConfigurationParser string
|
||||
|
||||
// The file parsing options that are available for a server configuration file.
|
||||
const (
|
||||
File = "file"
|
||||
Yaml = "yaml"
|
||||
Properties = "properties"
|
||||
Ini = "ini"
|
||||
Json = "json"
|
||||
Xml = "xml"
|
||||
)
|
||||
|
||||
// Defines a configuration file for the server startup. These will be looped over
|
||||
// and modified before the server finishes booting.
|
||||
type ConfigurationFile struct {
|
||||
FileName string `json:"file"`
|
||||
Parser ConfigurationParser `json:"parser"`
|
||||
Replace []ConfigurationFileReplacement `json:"replace"`
|
||||
}
|
||||
|
||||
// Defines a single find/replace instance for a given server configuration file.
|
||||
type ConfigurationFileReplacement struct {
|
||||
Match string `json:"match"`
|
||||
Value string `json:"value"`
|
||||
ValueType jsonparser.ValueType `json:"-"`
|
||||
}
|
||||
|
||||
func (cfr *ConfigurationFileReplacement) UnmarshalJSON(data []byte) error {
|
||||
if m, err := jsonparser.GetString(data, "match"); err != nil {
|
||||
return err
|
||||
} else {
|
||||
cfr.Match = m
|
||||
}
|
||||
|
||||
if v, dt, _, err := jsonparser.Get(data, "value"); err != nil {
|
||||
return err
|
||||
} else {
|
||||
if dt != jsonparser.String && dt != jsonparser.Number && dt != jsonparser.Boolean {
|
||||
return errors.New(
|
||||
fmt.Sprintf("cannot parse JSON: received unexpected replacement value type: %d", dt),
|
||||
)
|
||||
}
|
||||
|
||||
cfr.Value = string(v)
|
||||
cfr.ValueType = dt
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Parses a given configuration file and updates all of the values within as defined
|
||||
// in the API response from the Panel.
|
||||
func (f *ConfigurationFile) Parse(path string) error {
|
||||
zap.S().Debugw("parsing configuration file", zap.String("path", path), zap.String("parser", string(f.Parser)))
|
||||
|
||||
switch f.Parser {
|
||||
case Properties:
|
||||
f.parsePropertiesFile(path)
|
||||
break
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Parses a properties file and updates the values within it to match those that
|
||||
// are passed. Writes the file once completed.
|
||||
func (f *ConfigurationFile) parsePropertiesFile(path string) error {
|
||||
p, err := properties.LoadFile(path, properties.UTF8)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
for _, replace := range f.Replace {
|
||||
if _, _, err := p.Set(replace.Match, replace.Value); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
}
|
||||
|
||||
w, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0644);
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
_, err = p.Write(w, properties.UTF8)
|
||||
|
||||
return err
|
||||
}
|
33
server/config_parser.go
Normal file
33
server/config_parser.go
Normal file
|
@ -0,0 +1,33 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"go.uber.org/zap"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Parent function that will update all of the defined configuration files for a server
|
||||
// automatically to ensure that they always use the specified values.
|
||||
func (s *Server) UpdateConfigurationFiles() {
|
||||
wg := new(sync.WaitGroup)
|
||||
|
||||
for _, v := range s.processConfiguration.ConfigurationFiles {
|
||||
wg.Add(1)
|
||||
|
||||
go func(server *Server) {
|
||||
defer wg.Done()
|
||||
|
||||
p, err := s.Filesystem.SafePath(v.FileName)
|
||||
if err != nil {
|
||||
zap.S().Errorw("failed to generate safe path for configuration file", zap.String("server", server.Uuid), zap.Error(err))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if err := v.Parse(p); err != nil {
|
||||
zap.S().Errorw("failed to parse and update server configuration file", zap.String("server", server.Uuid), zap.Error(err))
|
||||
}
|
||||
}(s)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
}
|
|
@ -261,6 +261,13 @@ func (d *DockerEnvironment) Start() error {
|
|||
}
|
||||
}
|
||||
|
||||
// Update the configuration files defined for the server before beginning the boot process.
|
||||
// This process executes a bunch of parallel updates, so we just block until that process
|
||||
// is completed. Any errors as a result of this will just be bubbled out in the logger,
|
||||
// we don't need to actively do anything about it at this point, worst comes to worst the
|
||||
// server starts in a weird state and the user can manually adjust.
|
||||
d.Server.UpdateConfigurationFiles()
|
||||
|
||||
// Reset the permissions on files for the server before actually trying
|
||||
// to start it.
|
||||
if err := d.Server.Filesystem.Chown("/"); err != nil {
|
||||
|
|
Loading…
Reference in New Issue
Block a user