$ ./dhcp daemon
```
+If given `-pidfile <path>` arguments after 'daemon', the dhcp plugin will write
+its PID to the given file.
+
Alternatively, you can use systemd socket activation protocol.
Be sure that the .socket file uses /run/cni/dhcp.sock as the socket path.
"encoding/json"
"errors"
"fmt"
- "log"
+ "io/ioutil"
"net"
"net/http"
"net/rpc"
}
}
-func runDaemon() {
+func runDaemon(pidfilePath string) error {
// since other goroutines (on separate threads) will change namespaces,
// ensure the RPC server does not get scheduled onto those
runtime.LockOSThread()
+ // Write the pidfile
+ if pidfilePath != "" {
+ if !filepath.IsAbs(pidfilePath) {
+ return fmt.Errorf("Error writing pidfile %q: path not absolute", pidfilePath)
+ }
+ if err := ioutil.WriteFile(pidfilePath, []byte(fmt.Sprintf("%d", os.Getpid())), 0644); err != nil {
+ return fmt.Errorf("Error writing pidfile %q: %v", pidfilePath, err)
+ }
+ }
+
l, err := getListener()
if err != nil {
- log.Printf("Error getting listener: %v", err)
- return
+ return fmt.Errorf("Error getting listener: %v", err)
}
dhcp := newDHCP()
rpc.Register(dhcp)
rpc.HandleHTTP()
http.Serve(l, nil)
+ return nil
}
package main
import (
+ "flag"
"fmt"
+ "log"
"net/rpc"
"os"
"path/filepath"
func main() {
if len(os.Args) > 1 && os.Args[1] == "daemon" {
- runDaemon()
+ var pidfilePath string
+ daemonFlags := flag.NewFlagSet("daemon", flag.ExitOnError)
+ daemonFlags.StringVar(&pidfilePath, "pidfile", "", "optional path to write daemon PID to")
+ daemonFlags.Parse(os.Args[2:])
+
+ if err := runDaemon(pidfilePath); err != nil {
+ log.Printf(err.Error())
+ os.Exit(1)
+ }
} else {
skel.PluginMain(cmdAdd, cmdDel, version.All)
}