implement daemonization

This commit is contained in:
mykola2312 2025-01-25 00:55:02 +02:00
parent 451b73b0f2
commit 2d7625101f
3 changed files with 69 additions and 10 deletions

6
go.mod
View file

@ -6,3 +6,9 @@ require (
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
) )
require (
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
github.com/sevlyar/go-daemon v0.1.6
golang.org/x/sys v0.29.0 // indirect
)

6
go.sum
View file

@ -1,6 +1,12 @@
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA=
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/sevlyar/go-daemon v0.1.6 h1:EUh1MDjEM4BI109Jign0EaknA2izkOyi0LV3ro3QQGs=
github.com/sevlyar/go-daemon v0.1.6/go.mod h1:6dJpPatBT9eUwM5VCw9Bt6CdX9Tk6UWvhW3MebLDRKE=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=

67
main.go
View file

@ -10,10 +10,12 @@ import (
"lux/rpc" "lux/rpc"
"os" "os"
"os/signal" "os/signal"
"strconv"
"strings" "strings"
"syscall" "syscall"
"github.com/op/go-logging" "github.com/op/go-logging"
"github.com/sevlyar/go-daemon"
) )
var isNode bool var isNode bool
@ -117,6 +119,45 @@ func bootstrapNode() {
var log = logging.MustGetLogger("main") var log = logging.MustGetLogger("main")
func becomeDaemon() {
cwd, err := os.Getwd()
if err != nil {
log.Criticalf("Getwd failed: %v", err)
os.Exit(1)
}
ctx := &daemon.Context{
PidFileName: pidPath,
PidFilePerm: 0644,
WorkDir: cwd,
Umask: 027,
}
dmn, err := ctx.Reborn()
if err != nil {
log.Criticalf("ctx.Reborn failed: %v", err)
os.Exit(1)
}
if dmn != nil {
ctx.Release()
// parent process no longer needed
os.Exit(0)
}
defer ctx.Release()
// -- WE ARE NOW THE DAEMON --
// write pid
if pidPath != "" {
pidFile, _ := os.OpenFile(pidPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
defer pidFile.Close()
pidBytes := []byte(strconv.Itoa(os.Getpid()))
pidFile.Write(pidBytes)
}
}
func nodeMain() { func nodeMain() {
xmlBytes, err := os.ReadFile(configPath) xmlBytes, err := os.ReadFile(configPath)
if err != nil { if err != nil {
@ -126,13 +167,19 @@ func nodeMain() {
var config NodeConfig var config NodeConfig
if err := xml.Unmarshal(xmlBytes, &config); err != nil { if err := xml.Unmarshal(xmlBytes, &config); err != nil {
log.Criticalf("failed to parse xml: %v\n", err) log.Criticalf("failed to parse xml: %v", err)
os.Exit(1) os.Exit(1)
} }
// setup logging // setup logging
setupLogging(config.Log) setupLogging(config.Log)
// only after logging setup, we may became daemon
println(pidPath)
if daemonize {
becomeDaemon()
}
// check presense of keystore and id in config // check presense of keystore and id in config
if config.KeyStore == "" { if config.KeyStore == "" {
log.Critical("no keystore path specified!") log.Critical("no keystore path specified!")
@ -145,14 +192,14 @@ func nodeMain() {
nodeId, err := proto.ParseLuxID(config.ID) nodeId, err := proto.ParseLuxID(config.ID)
if err != nil { if err != nil {
log.Criticalf("failed to parse node id: %v\n", err) log.Criticalf("failed to parse node id: %v", err)
os.Exit(1) os.Exit(1)
} }
// load keystore // load keystore
ks := crypto.NewLuxKeyStore(config.KeyStore) ks := crypto.NewLuxKeyStore(config.KeyStore)
if err := ks.Load(); err != nil { if err := ks.Load(); err != nil {
log.Criticalf("failed to laod keystore: %v\n", err) log.Criticalf("failed to laod keystore: %v", err)
os.Exit(1) os.Exit(1)
} }
@ -168,13 +215,13 @@ func nodeMain() {
// add interior exterior channels // add interior exterior channels
for _, interior := range config.Interior { for _, interior := range config.Interior {
if err := node.AddInterior(interior); err != nil { if err := node.AddInterior(interior); err != nil {
log.Criticalf("failed to add interior %s: %v\n", interior, err) log.Criticalf("failed to add interior %s: %v", interior, err)
os.Exit(1) os.Exit(1)
} }
} }
for _, exterior := range config.Exterior { for _, exterior := range config.Exterior {
if err := node.AddExterior(exterior); err != nil { if err := node.AddExterior(exterior); err != nil {
log.Criticalf("failed to add exterior %s: %v\n", exterior, err) log.Criticalf("failed to add exterior %s: %v", exterior, err)
os.Exit(1) os.Exit(1)
} }
} }
@ -183,12 +230,12 @@ func nodeMain() {
for _, neighbor := range config.Neighbors { for _, neighbor := range config.Neighbors {
neighId, err := proto.ParseLuxID(neighbor.ID) neighId, err := proto.ParseLuxID(neighbor.ID)
if err != nil { if err != nil {
log.Criticalf("failed to parse neigh id %s: %v\n", neighbor.ID, err) log.Criticalf("failed to parse neigh id %s: %v", neighbor.ID, err)
os.Exit(1) os.Exit(1)
} }
if err := node.AddNeighbor(neighId, neighbor.Address); err != nil { if err := node.AddNeighbor(neighId, neighbor.Address); err != nil {
log.Criticalf("failed to add neighbor %s: %v\n", neighbor.ID, err) log.Criticalf("failed to add neighbor %s: %v", neighbor.ID, err)
os.Exit(1) os.Exit(1)
} }
} }
@ -203,14 +250,14 @@ func nodeMain() {
path := rpcPath[7:] path := rpcPath[7:]
if err := sv.AddEndpoint("unix", path, rpc.LuxRpcTypeRoot); err != nil { if err := sv.AddEndpoint("unix", path, rpc.LuxRpcTypeRoot); err != nil {
log.Criticalf("failed to add root rpc %s: %v\n", path, err) log.Criticalf("failed to add root rpc %s: %v", path, err)
os.Exit(1) os.Exit(1)
} }
} else if strings.HasPrefix(rpcPath, "tcp://") { } else if strings.HasPrefix(rpcPath, "tcp://") {
path := rpcPath[6:] path := rpcPath[6:]
if err := sv.AddEndpoint("tcp", path, rpc.LuxRpcTypeQuery); err != nil { if err := sv.AddEndpoint("tcp", path, rpc.LuxRpcTypeQuery); err != nil {
log.Criticalf("failed to add query rpc %s: %v\n", path, err) log.Criticalf("failed to add query rpc %s: %v", path, err)
os.Exit(1) os.Exit(1)
} }
} else { } else {
@ -364,7 +411,7 @@ func main() {
flag.StringVar(&configPath, "config", "", "node or host config") flag.StringVar(&configPath, "config", "", "node or host config")
flag.BoolVar(&bootstrap, "bootstrap", false, "bootstrap node keystore. config must be specified") flag.BoolVar(&bootstrap, "bootstrap", false, "bootstrap node keystore. config must be specified")
flag.BoolVar(&justNodeId, "just-node-id", false, "when bootstrapping only output node id to stdout") flag.BoolVar(&justNodeId, "just-node-id", false, "when bootstrapping only output node id to stdout")
flag.BoolVar(&daemonize, "daemonize", false, "run LUX as daemon in background") flag.BoolVar(&daemonize, "daemon", false, "run LUX as daemon in background")
flag.StringVar(&pidPath, "pid", "", "after daemonization LUX will write its PID here") flag.StringVar(&pidPath, "pid", "", "after daemonization LUX will write its PID here")
flag.StringVar(&rpcPath, "rpc", "", "Run as RPC client, specify path to RPC UNIX socket or TCP socket, must be in unix:// or tcp:// form") flag.StringVar(&rpcPath, "rpc", "", "Run as RPC client, specify path to RPC UNIX socket or TCP socket, must be in unix:// or tcp:// form")