Browse Source

cmd: Add pidfile support (closes #3235)

master
Matthew Holt 5 years ago
parent
commit
4df56c77e3
No known key found for this signature in database GPG Key ID: 2A349DD577D586A5
  1. 23
      admin.go
  2. 3
      caddy.go
  3. 15
      cmd/commandfuncs.go
  4. 6
      cmd/commands.go

23
admin.go

@ -21,6 +21,7 @@ import (
"expvar" "expvar"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"net" "net"
"net/http" "net/http"
"net/http/pprof" "net/http/pprof"
@ -546,13 +547,6 @@ func handleUnload(w http.ResponseWriter, r *http.Request) error {
Err: fmt.Errorf("method not allowed"), Err: fmt.Errorf("method not allowed"),
} }
} }
currentCfgMu.RLock()
hasCfg := currentCfg != nil
currentCfgMu.RUnlock()
if !hasCfg {
Log().Named("admin.api").Info("nothing to unload")
return nil
}
Log().Named("admin.api").Info("unloading") Log().Named("admin.api").Info("unloading")
if err := stopAndCleanup(); err != nil { if err := stopAndCleanup(); err != nil {
Log().Named("admin.api").Error("error unloading", zap.Error(err)) Log().Named("admin.api").Error("error unloading", zap.Error(err))
@ -801,12 +795,27 @@ var (
} }
) )
// PIDFile writes a pidfile to the file at filename. It
// will get deleted before the process gracefully exits.
func PIDFile(filename string) error {
pid := []byte(strconv.Itoa(os.Getpid()) + "\n")
err := ioutil.WriteFile(filename, pid, 0644)
if err != nil {
return err
}
pidfile = filename
return nil
}
// idRegexp is used to match ID fields and their associated values // idRegexp is used to match ID fields and their associated values
// in the config. It also matches adjacent commas so that syntax // in the config. It also matches adjacent commas so that syntax
// can be preserved no matter where in the object the field appears. // can be preserved no matter where in the object the field appears.
// It supports string and most numeric values. // It supports string and most numeric values.
var idRegexp = regexp.MustCompile(`(?m),?\s*"` + idKey + `"\s*:\s*(-?[0-9]+(\.[0-9]+)?|(?U)".*")\s*,?`) var idRegexp = regexp.MustCompile(`(?m),?\s*"` + idKey + `"\s*:\s*(-?[0-9]+(\.[0-9]+)?|(?U)".*")\s*,?`)
// pidfile is the name of the pidfile, if any.
var pidfile string
const ( const (
rawConfigKey = "config" rawConfigKey = "config"
idKey = "@id" idKey = "@id"

3
caddy.go

@ -470,6 +470,9 @@ func stopAndCleanup() error {
return err return err
} }
certmagic.CleanUpOwnLocks() certmagic.CleanUpOwnLocks()
if pidfile != "" {
os.Remove(pidfile)
}
return nil return nil
} }

15
cmd/commandfuncs.go

@ -41,6 +41,7 @@ import (
func cmdStart(fl Flags) (int, error) { func cmdStart(fl Flags) (int, error) {
startCmdConfigFlag := fl.String("config") startCmdConfigFlag := fl.String("config")
startCmdConfigAdapterFlag := fl.String("adapter") startCmdConfigAdapterFlag := fl.String("adapter")
startCmdPidfileFlag := fl.String("pidfile")
startCmdWatchFlag := fl.Bool("watch") startCmdWatchFlag := fl.Bool("watch")
// open a listener to which the child process will connect when // open a listener to which the child process will connect when
@ -71,6 +72,9 @@ func cmdStart(fl Flags) (int, error) {
if startCmdWatchFlag { if startCmdWatchFlag {
cmd.Args = append(cmd.Args, "--watch") cmd.Args = append(cmd.Args, "--watch")
} }
if startCmdPidfileFlag != "" {
cmd.Args = append(cmd.Args, "--pidfile", startCmdPidfileFlag)
}
stdinpipe, err := cmd.StdinPipe() stdinpipe, err := cmd.StdinPipe()
if err != nil { if err != nil {
return caddy.ExitCodeFailedStartup, return caddy.ExitCodeFailedStartup,
@ -149,6 +153,7 @@ func cmdRun(fl Flags) (int, error) {
runCmdResumeFlag := fl.Bool("resume") runCmdResumeFlag := fl.Bool("resume")
runCmdPrintEnvFlag := fl.Bool("environ") runCmdPrintEnvFlag := fl.Bool("environ")
runCmdWatchFlag := fl.Bool("watch") runCmdWatchFlag := fl.Bool("watch")
runCmdPidfileFlag := fl.String("pidfile")
runCmdPingbackFlag := fl.String("pingback") runCmdPingbackFlag := fl.String("pingback")
// if we are supposed to print the environment, do that first // if we are supposed to print the environment, do that first
@ -225,6 +230,16 @@ func cmdRun(fl Flags) (int, error) {
go watchConfigFile(configFile, runCmdConfigAdapterFlag) go watchConfigFile(configFile, runCmdConfigAdapterFlag)
} }
// create pidfile
if runCmdPidfileFlag != "" {
err := caddy.PIDFile(runCmdPidfileFlag)
if err != nil {
caddy.Log().Error("unable to write PID file",
zap.String("pidfile", runCmdPidfileFlag),
zap.Error(err))
}
}
// warn if the environment does not provide enough information about the disk // warn if the environment does not provide enough information about the disk
hasXDG := os.Getenv("XDG_DATA_HOME") != "" && hasXDG := os.Getenv("XDG_DATA_HOME") != "" &&
os.Getenv("XDG_CONFIG_HOME") != "" && os.Getenv("XDG_CONFIG_HOME") != "" &&

6
cmd/commands.go

@ -74,7 +74,7 @@ func init() {
RegisterCommand(Command{ RegisterCommand(Command{
Name: "start", Name: "start",
Func: cmdStart, Func: cmdStart,
Usage: "[--config <path> [--adapter <name>]] [--watch]", Usage: "[--config <path> [--adapter <name>]] [--watch] [--pidfile <file>]",
Short: "Starts the Caddy process in the background and then returns", Short: "Starts the Caddy process in the background and then returns",
Long: ` Long: `
Starts the Caddy process, optionally bootstrapped with an initial config file. Starts the Caddy process, optionally bootstrapped with an initial config file.
@ -87,6 +87,7 @@ using 'caddy run' instead to keep it in the foreground.`,
fs := flag.NewFlagSet("start", flag.ExitOnError) fs := flag.NewFlagSet("start", flag.ExitOnError)
fs.String("config", "", "Configuration file") fs.String("config", "", "Configuration file")
fs.String("adapter", "", "Name of config adapter to apply") fs.String("adapter", "", "Name of config adapter to apply")
fs.String("pidfile", "", "Path of file to which to write process ID")
fs.Bool("watch", false, "Reload changed config file automatically") fs.Bool("watch", false, "Reload changed config file automatically")
return fs return fs
}(), }(),
@ -95,7 +96,7 @@ using 'caddy run' instead to keep it in the foreground.`,
RegisterCommand(Command{ RegisterCommand(Command{
Name: "run", Name: "run",
Func: cmdRun, Func: cmdRun,
Usage: "[--config <path> [--adapter <name>]] [--environ] [--watch]", Usage: "[--config <path> [--adapter <name>]] [--environ] [--resume] [--watch] [--pidfile <fil>]",
Short: `Starts the Caddy process and blocks indefinitely`, Short: `Starts the Caddy process and blocks indefinitely`,
Long: ` Long: `
Starts the Caddy process, optionally bootstrapped with an initial config file, Starts the Caddy process, optionally bootstrapped with an initial config file,
@ -132,6 +133,7 @@ development environment.`,
fs.Bool("environ", false, "Print environment") fs.Bool("environ", false, "Print environment")
fs.Bool("resume", false, "Use saved config, if any (and prefer over --config file)") fs.Bool("resume", false, "Use saved config, if any (and prefer over --config file)")
fs.Bool("watch", false, "Watch config file for changes and reload it automatically") fs.Bool("watch", false, "Watch config file for changes and reload it automatically")
fs.String("pidfile", "", "Path of file to which to write process ID")
fs.String("pingback", "", "Echo confirmation bytes to this address on success") fs.String("pingback", "", "Echo confirmation bytes to this address on success")
return fs return fs
}(), }(),

Loading…
Cancel
Save