diff --git a/command/server.go b/command/server.go index 4209d80312a5..e089ef22c56d 100644 --- a/command/server.go +++ b/command/server.go @@ -660,6 +660,18 @@ CLUSTER_SYNTHESIS_COMPLETE: // Release the log gate. c.logGate.Flush() + // Write out the PID to the file now that server has successfully started + if err := c.storePidFile(config.PidFile); err != nil { + c.Ui.Output(fmt.Sprintf("Error storing PID: %v", err)) + return 1 + } + + defer func() { + if err := c.removePidFile(config.PidFile); err != nil { + c.Ui.Output(fmt.Sprintf("Error deleting the PID file: %v", err)) + } + }() + // Wait for shutdown shutdownTriggered := false @@ -1226,6 +1238,37 @@ func (c *ServerCommand) AutocompleteFlags() complete.Flags { } } +// storePidFile is used to write out our PID to a file if necessary +func (c *ServerCommand) storePidFile(pidPath string) error { + // Quit fast if no pidfile + if pidPath == "" { + return nil + } + + // Open the PID file + pidFile, err := os.OpenFile(pidPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) + if err != nil { + return fmt.Errorf("could not open pid file: %v", err) + } + defer pidFile.Close() + + // Write out the PID + pid := os.Getpid() + _, err = pidFile.WriteString(fmt.Sprintf("%d", pid)) + if err != nil { + return fmt.Errorf("could not write to pid file: %v", err) + } + return nil +} + +// removePidFile is used to cleanup the PID file if necessary +func (c *ServerCommand) removePidFile(pidPath string) error { + if pidPath == "" { + return nil + } + return os.Remove(pidPath) +} + // MakeShutdownCh returns a channel that can be used for shutdown // notifications for commands. This channel will send a message for every // SIGINT or SIGTERM received. diff --git a/command/server/config.go b/command/server/config.go index 7c20a371ffde..8f78ac0ad272 100644 --- a/command/server/config.go +++ b/command/server/config.go @@ -47,6 +47,7 @@ type Config struct { PluginDirectory string `hcl:"plugin_directory"` + PidFile string `hcl:"pid_file"` EnableRawEndpoint bool `hcl:"-"` EnableRawEndpointRaw interface{} `hcl:"raw_storage_endpoint"` } @@ -302,6 +303,11 @@ func (c *Config) Merge(c2 *Config) *Config { result.PluginDirectory = c2.PluginDirectory } + result.PidFile = c.PidFile + if c2.PidFile != "" { + result.PidFile = c2.PidFile + } + return result } @@ -399,6 +405,7 @@ func ParseConfig(d string, logger log.Logger) (*Config, error) { "cluster_name", "cluster_cipher_suites", "plugin_directory", + "pid_file", "raw_storage_endpoint", } if err := checkHCLKeys(list, valid); err != nil { diff --git a/command/server/config_test.go b/command/server/config_test.go index 8e0efe70406b..bdc9128e553a 100644 --- a/command/server/config_test.go +++ b/command/server/config_test.go @@ -70,6 +70,8 @@ func TestLoadConfigFile(t *testing.T) { DefaultLeaseTTL: 10 * time.Hour, DefaultLeaseTTLRaw: "10h", ClusterName: "testcluster", + + PidFile: "./pidfile", } if !reflect.DeepEqual(config, expected) { t.Fatalf("expected \n\n%#v\n\n to be \n\n%#v\n\n", config, expected) @@ -123,16 +125,16 @@ func TestLoadConfigFile_json(t *testing.T) { CirconusBrokerSelectTag: "", }, - MaxLeaseTTL: 10 * time.Hour, - MaxLeaseTTLRaw: "10h", - DefaultLeaseTTL: 10 * time.Hour, - DefaultLeaseTTLRaw: "10h", - ClusterName: "testcluster", - DisableCacheRaw: interface{}(nil), - DisableMlockRaw: interface{}(nil), - EnableUI: true, - EnableUIRaw: true, - + MaxLeaseTTL: 10 * time.Hour, + MaxLeaseTTLRaw: "10h", + DefaultLeaseTTL: 10 * time.Hour, + DefaultLeaseTTLRaw: "10h", + ClusterName: "testcluster", + DisableCacheRaw: interface{}(nil), + DisableMlockRaw: interface{}(nil), + EnableUI: true, + EnableUIRaw: true, + PidFile: "./pidfile", EnableRawEndpoint: true, EnableRawEndpointRaw: true, } diff --git a/command/server/test-fixtures/config.hcl b/command/server/test-fixtures/config.hcl index f4866d8cb0c0..0a84f7b3f4e3 100644 --- a/command/server/test-fixtures/config.hcl +++ b/command/server/test-fixtures/config.hcl @@ -28,4 +28,5 @@ telemetry { max_lease_ttl = "10h" default_lease_ttl = "10h" cluster_name = "testcluster" -raw_storage_endpoint = true \ No newline at end of file +pid_file = "./pidfile" +raw_storage_endpoint = true diff --git a/command/server/test-fixtures/config.hcl.json b/command/server/test-fixtures/config.hcl.json index fc1fda099cf5..918af5680305 100644 --- a/command/server/test-fixtures/config.hcl.json +++ b/command/server/test-fixtures/config.hcl.json @@ -18,5 +18,6 @@ "default_lease_ttl": "10h", "cluster_name":"testcluster", "ui":true, + "pid_file":"./pidfile", "raw_storage_endpoint":true } diff --git a/website/source/docs/configuration/index.html.md b/website/source/docs/configuration/index.html.md index a4da60ffcf35..d6f26203ebf5 100644 --- a/website/source/docs/configuration/index.html.md +++ b/website/source/docs/configuration/index.html.md @@ -109,6 +109,9 @@ to specify where the configuration is. the standard Vault API address will automatically redirect there. This can also be provided via the environment variable `VAULT_UI`. +- `pid_file` `(string: "")` - Path to the file in which the Vault server's + Process ID (PID) should be stored. + [storage-backend]: /docs/configuration/storage/index.html [listener]: /docs/configuration/listener/index.html [telemetry]: /docs/configuration/telemetry.html