Skip to content

Commit

Permalink
Config system
Browse files Browse the repository at this point in the history
(see also issue mumble-voip#21)
Removes synchronizing set config keys to freezelog,
since the system is the preferred way to persist configuration.
  • Loading branch information
rubenseyer committed Apr 16, 2020
1 parent 6f8c2bf commit 40ef449
Show file tree
Hide file tree
Showing 11 changed files with 263 additions and 88 deletions.
24 changes: 13 additions & 11 deletions cmd/grumble/args.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ var usageTmpl = `usage: grumble [options]
--log <log-path> (default: $DATADIR/grumble.log)
Log file path.
--ini <config-path> (default: $DATADIR/grumble.ini)
Config file path.
--regen-keys
Force grumble to regenerate its global RSA
keypair (and certificate).
Expand All @@ -46,12 +49,13 @@ var usageTmpl = `usage: grumble [options]
`

type args struct {
ShowHelp bool
DataDir string
LogPath string
RegenKeys bool
SQLiteDB string
CleanUp bool
ShowHelp bool
DataDir string
LogPath string
ConfigPath string
RegenKeys bool
SQLiteDB string
CleanUp bool
}

func defaultDataDir() string {
Expand All @@ -63,10 +67,6 @@ func defaultDataDir() string {
return filepath.Join(homedir, dirname)
}

func defaultLogPath() string {
return filepath.Join(defaultDataDir(), "grumble.log")
}

func Usage() {
t, err := template.New("usage").Parse(usageTmpl)
if err != nil {
Expand All @@ -92,7 +92,9 @@ func init() {

flag.BoolVar(&Args.ShowHelp, "help", false, "")
flag.StringVar(&Args.DataDir, "datadir", defaultDataDir(), "")
flag.StringVar(&Args.LogPath, "log", defaultLogPath(), "")
flag.StringVar(&Args.LogPath, "log", "", "")
flag.StringVar(&Args.ConfigPath, "ini", "", "")

flag.BoolVar(&Args.RegenKeys, "regen-keys", false, "")

flag.StringVar(&Args.SQLiteDB, "import-murmurdb", "", "")
Expand Down
32 changes: 2 additions & 30 deletions cmd/grumble/freeze.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
"mumble.info/grumble/pkg/ban"
"mumble.info/grumble/pkg/freezer"
"mumble.info/grumble/pkg/mumbleproto"
"mumble.info/grumble/pkg/serverconf"
)

// Freeze a server to disk and closes the log file.
Expand Down Expand Up @@ -74,7 +73,7 @@ func (server *Server) Freeze() (fs *freezer.Server, err error) {
fs = new(freezer.Server)

// Freeze all config kv-pairs
allCfg := server.cfg.GetAll()
allCfg := server.cfg.GetAllPersistent()
for k, v := range allCfg {
fs.Config = append(fs.Config, &freezer.ConfigKeyValuePair{
Key: proto.String(k),
Expand Down Expand Up @@ -420,11 +419,10 @@ func NewServerFromFrozen(name string) (s *Server, err error) {
}
}

s, err = NewServer(id)
s, err = NewServer(id, configFile.ServerConfig(id, cfgMap))
if err != nil {
return nil, err
}
s.cfg = serverconf.New(cfgMap)

// Unfreeze the server's frozen bans.
s.UnfreezeBanList(fs.BanList)
Expand Down Expand Up @@ -835,29 +833,3 @@ func (server *Server) UpdateFrozenBans(bans []ban.Ban) {
}
server.numLogOps += 1
}

// UpdateConfig writes an updated config value to the datastore.
func (server *Server) UpdateConfig(key, value string) {
fcfg := &freezer.ConfigKeyValuePair{
Key: proto.String(key),
Value: proto.String(value),
}
err := server.freezelog.Put(fcfg)
if err != nil {
server.Fatal(err)
}
server.numLogOps += 1
}

// ResetConfig writes to the freezelog that the config with key
// has been reset to its default value.
func (server *Server) ResetConfig(key string) {
fcfg := &freezer.ConfigKeyValuePair{
Key: proto.String(key),
}
err := server.freezelog.Put(fcfg)
if err != nil {
server.Fatal(err)
}
server.numLogOps += 1
}
65 changes: 58 additions & 7 deletions cmd/grumble/grumble.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ import (

"mumble.info/grumble/pkg/blobstore"
"mumble.info/grumble/pkg/logtarget"
"mumble.info/grumble/pkg/serverconf"
)

var servers map[int64]*Server
var blobStore blobstore.BlobStore
var configFile *serverconf.ConfigFile

func main() {
var err error
Expand All @@ -36,10 +38,42 @@ func main() {
}
dataDir.Close()

// Open the config file
var configFn string
if Args.ConfigPath != "" {
configFn = Args.ConfigPath
} else {
configFn = filepath.Join(Args.DataDir, "grumble.ini")
}
if filepath.Ext(configFn) == ".ini" {
// Create it if it doesn't exist
configFd, err := os.OpenFile(configFn, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0700)
if err == nil {
configFd.WriteString(serverconf.DefaultConfigFile)
log.Fatalf("Default config written to %v\n", configFn)
configFd.Close()
} else if err != nil && !os.IsExist(err) {
log.Fatalf("Unable to open config file (%v): %v", configFn, err)
return
}
}
configFile, err = serverconf.NewConfigFile(configFn)
if err != nil {
log.Fatalf("Unable to open config file (%v): %v", configFn, err)
return
}
config := configFile.GlobalConfig()

// Set up logging
var logFn string
if Args.LogPath != "" {
logFn = Args.LogPath
} else {
logFn = config.PathValue("LogPath", Args.DataDir)
}
logtarget.Default, err = logtarget.OpenFile(Args.LogPath, os.Stderr)
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to open log file (%v): %v", Args.LogPath, err)
fmt.Fprintf(os.Stderr, "Unable to open log file (%v): %v", logFn, err)
return
}
log.SetPrefix("[G] ")
Expand All @@ -48,6 +82,23 @@ func main() {
log.Printf("Grumble")
log.Printf("Using data directory: %s", Args.DataDir)

// Warn on some unsupported configuration options for users migrating from Murmur
if config.StringValue("database") != "" {
log.Println("* Grumble does not yet support Murmur databases directly (see issue #21 on github).")
if driver := config.StringValue("dbDriver"); driver == "QSQLITE" {
log.Println(" To convert a previous SQLite database, use the --import-murmurdb flag.")
}
}
if config.StringValue("sslDHParams") != "" {
log.Println("* Go does not implement DHE modes in TLS, so the configured dhparams are ignored.")
}
if config.StringValue("ice") != "" {
log.Println("* Grumble does not support ZeroC ICE.")
}
if config.StringValue("grpc") != "" {
log.Println("* Grumble does not yet support gRPC (see issue #23 on github).")
}

// Open the blobstore. If the directory doesn't
// already exist, create the directory and open
// the blobstore.
Expand All @@ -65,9 +116,9 @@ func main() {
// and corresponding certificate.
// These are used as the default certificate of all virtual servers
// and the SSH admin console, but can be overridden using the "key"
// and "cert" arguments to Grumble.
certFn := filepath.Join(Args.DataDir, "cert.pem")
keyFn := filepath.Join(Args.DataDir, "key.pem")
// and "cert" arguments to Grumble. todo(rubenseyer) implement override by cli
certFn := config.PathValue("CertPath", Args.DataDir)
keyFn := config.PathValue("KeyPath", Args.DataDir)
shouldRegen := false
if Args.RegenKeys {
shouldRegen = true
Expand Down Expand Up @@ -164,10 +215,10 @@ func main() {
if err != nil {
log.Fatalf("Unable to read file from data directory: %v", err.Error())
}
// The data dir file descriptor.
// The servers dir file descriptor.
err = serversDir.Close()
if err != nil {
log.Fatalf("Unable to close data directory: %v", err.Error())
log.Fatalf("Unable to close servers directory: %v", err.Error())
return
}

Expand All @@ -191,7 +242,7 @@ func main() {

// If no servers were found, create the default virtual server.
if len(servers) == 0 {
s, err := NewServer(1)
s, err := NewServer(1, configFile.ServerConfig(1, nil))
if err != nil {
log.Fatalf("Couldn't start server: %s", err.Error())
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/grumble/murmurdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func MurmurImport(filename string) (err error) {

// Create a new Server from a Murmur SQLite database
func NewServerFromSQLite(id int64, db *sql.DB) (s *Server, err error) {
s, err = NewServer(id)
s, err = NewServer(id, nil)
if err != nil {
return nil, err
}
Expand Down
27 changes: 8 additions & 19 deletions cmd/grumble/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
"log"
"net"
"net/http"
"path/filepath"
"strings"
"sync"
"time"
Expand Down Expand Up @@ -138,12 +137,16 @@ func (lf clientLogForwarder) Write(incoming []byte) (int, error) {
}

// Allocate a new Murmur instance
func NewServer(id int64) (s *Server, err error) {
func NewServer(id int64, config *serverconf.Config) (s *Server, err error) {
s = new(Server)

s.Id = id

s.cfg = serverconf.New(nil)
if config == nil {
s.cfg = serverconf.New(nil, nil)
} else {
s.cfg = config
}

s.Users = make(map[uint32]*User)
s.UserCertMap = make(map[string]*User)
Expand Down Expand Up @@ -191,10 +194,6 @@ func (server *Server) setConfigPassword(key, password string) {
// Could be racy, but shouldn't really matter...
val := "sha1$" + salt + "$" + digest
server.cfg.Set(key, val)

if server.cfgUpdate != nil {
server.cfgUpdate <- &KeyValuePair{Key: key, Value: val}
}
}

// SetSuperUserPassword sets password as the new SuperUser password
Expand Down Expand Up @@ -436,14 +435,6 @@ func (server *Server) handlerLoop() {
case client := <-server.clientAuthenticated:
server.finishAuthenticate(client)

// Disk freeze config update
case kvp := <-server.cfgUpdate:
if !kvp.Reset {
server.UpdateConfig(kvp.Key, kvp.Value)
} else {
server.ResetConfig(kvp.Key)
}

// Server registration update
// Tick every hour + a minute offset based on the server id.
case <-regtick:
Expand Down Expand Up @@ -1356,7 +1347,6 @@ func (server *Server) initPerLaunchData() {
server.bye = make(chan bool)
server.incoming = make(chan *Message)
server.voicebroadcast = make(chan *VoiceBroadcast)
server.cfgUpdate = make(chan *KeyValuePair)
server.tempRemove = make(chan *Channel, 1)
server.clientAuthenticated = make(chan *Client)
}
Expand All @@ -1371,7 +1361,6 @@ func (server *Server) cleanPerLaunchData() {
server.bye = nil
server.incoming = nil
server.voicebroadcast = nil
server.cfgUpdate = nil
server.tempRemove = nil
server.clientAuthenticated = nil
}
Expand Down Expand Up @@ -1460,8 +1449,8 @@ func (server *Server) Start() (err error) {
*/

// Wrap a TLS listener around the TCP connection
certFn := filepath.Join(Args.DataDir, "cert.pem")
keyFn := filepath.Join(Args.DataDir, "key.pem")
certFn := server.cfg.PathValue("CertPath", Args.DataDir)
keyFn := server.cfg.PathValue("KeyPath", Args.DataDir)
cert, err := tls.LoadX509KeyPair(certFn, keyFn)
if err != nil {
return err
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ require (
github.com/golang/protobuf v1.3.5
github.com/gorilla/websocket v1.4.2
golang.org/x/crypto v0.0.0-20200406173513-056763e48d71
gopkg.in/ini.v1 v1.55.0
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/ini.v1 v1.55.0 h1:E8yzL5unfpW3M6fz/eB7Cb5MQAYSZ7GKo4Qth+N2sgQ=
gopkg.in/ini.v1 v1.55.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
Loading

0 comments on commit 40ef449

Please sign in to comment.