mirror of https://github.com/status-im/consul.git
agent: beginning socket user/group/mode support as discussed in #612
This commit is contained in:
parent
1154b0cda6
commit
21dd95d9af
|
@ -23,13 +23,6 @@ const (
|
||||||
// Path to save local agent checks
|
// Path to save local agent checks
|
||||||
checksDir = "checks"
|
checksDir = "checks"
|
||||||
|
|
||||||
// errSocketFileExists is the human-friendly error message displayed when
|
|
||||||
// trying to bind a socket to an existing file.
|
|
||||||
errSocketFileExists = "A file exists at the requested socket path %q. " +
|
|
||||||
"If Consul was not shut down properly, the socket file may " +
|
|
||||||
"be left behind. If the path looks correct, remove the file " +
|
|
||||||
"and try again."
|
|
||||||
|
|
||||||
// The ID of the faux health checks for maintenance mode
|
// The ID of the faux health checks for maintenance mode
|
||||||
serviceMaintCheckPrefix = "_service_maintenance"
|
serviceMaintCheckPrefix = "_service_maintenance"
|
||||||
nodeMaintCheckID = "_node_maintenenace"
|
nodeMaintCheckID = "_node_maintenenace"
|
||||||
|
|
|
@ -295,11 +295,15 @@ func (c *Command) setupAgent(config *Config, logOutput io.Writer, logWriter *log
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error if we are trying to bind a domain socket to an existing path
|
// Clear the domain socket file if it exists
|
||||||
if path, ok := unixSocketAddr(config.Addresses.RPC); ok {
|
socketPath, isSocket := unixSocketAddr(config.Addresses.RPC)
|
||||||
if _, err := os.Stat(path); err == nil || !os.IsNotExist(err) {
|
if isSocket {
|
||||||
c.Ui.Output(fmt.Sprintf(errSocketFileExists, path))
|
if _, err := os.Stat(socketPath); !os.IsNotExist(err) {
|
||||||
return fmt.Errorf(errSocketFileExists, path)
|
agent.logger.Printf("[WARN] agent: Replacing socket %q", socketPath)
|
||||||
|
}
|
||||||
|
if err := os.Remove(socketPath); err != nil && !os.IsNotExist(err) {
|
||||||
|
c.Ui.Output(fmt.Sprintf("Error removing socket file: %s", err))
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,6 +314,15 @@ func (c *Command) setupAgent(config *Config, logOutput io.Writer, logWriter *log
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set up ownership/permission bits on the socket file
|
||||||
|
if isSocket {
|
||||||
|
if err := setFilePermissions(socketPath, config.UnixSockets); err != nil {
|
||||||
|
agent.Shutdown()
|
||||||
|
c.Ui.Error(fmt.Sprintf("Error setting up socket: %s", err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Start the IPC layer
|
// Start the IPC layer
|
||||||
c.Ui.Output("Starting Consul agent RPC...")
|
c.Ui.Output("Starting Consul agent RPC...")
|
||||||
c.rpcServer = NewAgentRPC(agent, rpcListener, logOutput, logWriter)
|
c.rpcServer = NewAgentRPC(agent, rpcListener, logOutput, logWriter)
|
||||||
|
|
|
@ -343,6 +343,9 @@ type Config struct {
|
||||||
|
|
||||||
// WatchPlans contains the compiled watches
|
// WatchPlans contains the compiled watches
|
||||||
WatchPlans []*watch.WatchPlan `mapstructure:"-" json:"-"`
|
WatchPlans []*watch.WatchPlan `mapstructure:"-" json:"-"`
|
||||||
|
|
||||||
|
// UnixSockets is a map of socket configuration data
|
||||||
|
UnixSockets map[string]string `mapstructure:"unix_sockets"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// unixSocketAddr tests if a given address describes a domain socket,
|
// unixSocketAddr tests if a given address describes a domain socket,
|
||||||
|
@ -893,6 +896,15 @@ func MergeConfig(a, b *Config) *Config {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(b.UnixSockets) != 0 {
|
||||||
|
if result.UnixSockets == nil {
|
||||||
|
result.UnixSockets = make(map[string]string)
|
||||||
|
}
|
||||||
|
for field, value := range b.UnixSockets {
|
||||||
|
result.UnixSockets[field] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Copy the start join addresses
|
// Copy the start join addresses
|
||||||
result.StartJoin = make([]string, 0, len(a.StartJoin)+len(b.StartJoin))
|
result.StartJoin = make([]string, 0, len(a.StartJoin)+len(b.StartJoin))
|
||||||
result.StartJoin = append(result.StartJoin, a.StartJoin...)
|
result.StartJoin = append(result.StartJoin, a.StartJoin...)
|
||||||
|
|
|
@ -96,9 +96,13 @@ func NewHTTPServers(agent *Agent, config *Config, logOutput io.Writer) ([]*HTTPS
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error if we are trying to bind a domain socket to an existing path
|
// Error if we are trying to bind a domain socket to an existing path
|
||||||
if path, ok := unixSocketAddr(config.Addresses.HTTP); ok {
|
socketPath, isSocket := unixSocketAddr(config.Addresses.HTTP)
|
||||||
if _, err := os.Stat(path); err == nil || !os.IsNotExist(err) {
|
if isSocket {
|
||||||
return nil, fmt.Errorf(errSocketFileExists, path)
|
if _, err := os.Stat(socketPath); !os.IsNotExist(err) {
|
||||||
|
agent.logger.Printf("[WARN] agent: Replacing socket %q", socketPath)
|
||||||
|
}
|
||||||
|
if err := os.Remove(socketPath); err != nil && !os.IsNotExist(err) {
|
||||||
|
return nil, fmt.Errorf("error removing socket file: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,6 +117,13 @@ func NewHTTPServers(agent *Agent, config *Config, logOutput io.Writer) ([]*HTTPS
|
||||||
list = tcpKeepAliveListener{ln.(*net.TCPListener)}
|
list = tcpKeepAliveListener{ln.(*net.TCPListener)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set up ownership/permission bits on the socket file
|
||||||
|
if isSocket {
|
||||||
|
if err := setFilePermissions(socketPath, config.UnixSockets); err != nil {
|
||||||
|
return nil, fmt.Errorf("Failed setting up HTTP socket: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create the mux
|
// Create the mux
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/hashicorp/go-msgpack/codec"
|
"github.com/hashicorp/go-msgpack/codec"
|
||||||
|
@ -97,3 +98,43 @@ func encodeMsgPack(msg interface{}) ([]byte, error) {
|
||||||
func stringHash(s string) string {
|
func stringHash(s string) string {
|
||||||
return fmt.Sprintf("%x", md5.Sum([]byte(s)))
|
return fmt.Sprintf("%x", md5.Sum([]byte(s)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setFilePermissions handles configuring ownership and permissions settings
|
||||||
|
// on a given file. It takes a map, which defines the permissions to be set.
|
||||||
|
// All permission/ownership settings are optional. If no user or group is
|
||||||
|
// specified, the current user/group will be used. Mode is optional, and has
|
||||||
|
// no default (the operation is not performed if absent).
|
||||||
|
func setFilePermissions(path string, perms map[string]string) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
uid, gid := os.Getuid(), os.Getgid()
|
||||||
|
if _, ok := perms["uid"]; ok {
|
||||||
|
if uid, err = strconv.Atoi(perms["uid"]); err != nil {
|
||||||
|
return fmt.Errorf("invalid user id specified: %v", perms["uid"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if _, ok := perms["gid"]; ok {
|
||||||
|
if gid, err = strconv.Atoi(perms["gid"]); err != nil {
|
||||||
|
return fmt.Errorf("invalid group id specified: %v", perms["gid"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := os.Chown(path, uid, gid); err != nil {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"failed setting ownership to %d:%d on %q: %s",
|
||||||
|
uid, gid, path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := perms["mode"]; ok {
|
||||||
|
mode, err := strconv.ParseUint(perms["mode"], 8, 32)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("invalid mode specified for %q: %s",
|
||||||
|
path, perms["mode"])
|
||||||
|
}
|
||||||
|
if err := os.Chmod(path, os.FileMode(mode)); err != nil {
|
||||||
|
return fmt.Errorf("failed setting permissions to %d on %q: %s",
|
||||||
|
mode, path, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue