summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--server.go37
-rw-r--r--server_config.go77
-rw-r--r--server_config_test.go42
-rw-r--r--server_test.go84
-rw-r--r--user.go31
-rw-r--r--user_test.go76
6 files changed, 68 insertions, 279 deletions
diff --git a/server.go b/server.go
index fb3c737f..d52c0b54 100644
--- a/server.go
+++ b/server.go
@@ -4,7 +4,6 @@ import (
"sync"
"os/exec"
"fmt"
- "errors"
)
const (
@@ -26,6 +25,9 @@ type Server struct {
// configures server, pool, cmd creation and factory.
cfg *ServerConfig
+ // worker command creator
+ cmd func() *exec.Cmd
+
// observes pool events (can be attached to multiple pools at the same time)
observer func(event int, ctx interface{})
@@ -35,9 +37,6 @@ type Server struct {
// indicates that server was started
started bool
- // worker command creator
- cmd func() *exec.Cmd
-
// creates and connects to workers
factory Factory
@@ -46,14 +45,17 @@ type Server struct {
}
// NewServer creates new router. Make sure to call configure before the usage.
-func NewServer(cfg *ServerConfig, o func(event int, ctx interface{})) *Server {
- return &Server{
- cfg: cfg,
- observer: o,
- }
+func NewServer(cmd func() *exec.Cmd, cfg *ServerConfig) *Server {
+ return &Server{cmd: cmd, cfg: cfg}
}
-// Reconfigure re-configures underlying pool and destroys it's previous version if any.
+// Observe attaches server event watcher.
+func (srv *Server) Observe(o func(event int, ctx interface{})) {
+ srv.observer = o
+}
+
+// Reconfigure re-configures underlying pool and destroys it's previous version if any. Reconfigure will ignore factory
+// and relay settings.
func (srv *Server) Reconfigure(cfg *ServerConfig) error {
srv.mu.Lock()
if !srv.started {
@@ -62,23 +64,18 @@ func (srv *Server) Reconfigure(cfg *ServerConfig) error {
}
srv.mu.Unlock()
- // we are not allowing factory or cmd changes while the server is running.
- if srv.cfg.Differs(cfg) {
- return errors.New("config change while running server (only pool config change is allowed)")
- }
-
srv.mu.Lock()
previous := srv.pool
srv.mu.Unlock()
- pool, err := NewPool(srv.cmd, srv.factory, *cfg.Pool)
+ pool, err := NewPool(srv.cmd, srv.factory, cfg.Pool)
if err != nil {
return err
}
srv.throw(EventNewPool, pool)
srv.mu.Lock()
- srv.cfg, srv.pool = cfg, pool
+ srv.cfg.Pool, srv.pool = cfg.Pool, pool
srv.pool.Observe(srv.poolObserver)
srv.mu.Unlock()
@@ -102,15 +99,11 @@ func (srv *Server) Start() (err error) {
srv.mu.Lock()
defer srv.mu.Unlock()
- if srv.cmd, err = srv.cfg.makeCommand(); err != nil {
- return err
- }
-
if srv.factory, err = srv.cfg.makeFactory(); err != nil {
return err
}
- if srv.pool, err = NewPool(srv.cmd, srv.factory, *srv.cfg.Pool); err != nil {
+ if srv.pool, err = NewPool(srv.cmd, srv.factory, srv.cfg.Pool); err != nil {
return err
}
diff --git a/server_config.go b/server_config.go
index 7e8aa80e..14bd7619 100644
--- a/server_config.go
+++ b/server_config.go
@@ -5,10 +5,6 @@ import (
"net"
"strings"
"time"
- "os/exec"
- "syscall"
- "os/user"
- "strconv"
)
const (
@@ -18,18 +14,6 @@ const (
// Server config combines factory, pool and cmd configurations.
type ServerConfig struct {
- // Command includes command strings with all the parameters, example: "php worker.php pipes". This config section
- // // must not change on re-configuration.
- Command string
-
- // User specifies what user to run command under, for Unix systems only. Support both UID and name options. Keep
- // empty to use current user.This config section must not change on re-configuration.
- User string
-
- // Group specifies what group to run command under, for Unix systems only. Support GID or name options. Keep empty
- // to use current user.This config section must not change on re-configuration.
- Group string
-
// Relay defines connection method and factory to be used to connect to workers:
// "pipes", "tcp://:6001", "unix://rr.sock"
// This config section must not change on re-configuration.
@@ -41,74 +25,15 @@ type ServerConfig struct {
// Pool defines worker pool configuration, number of workers, timeouts and etc. This config section might change
// while server is running.
- Pool *Config
+ Pool Config
}
// Differs returns true if configuration has changed but ignores pool changes.
func (cfg *ServerConfig) Differs(new *ServerConfig) bool {
- // command configuration has changed
- if cfg.Command != new.Command || cfg.User != new.User || cfg.Group != new.Group {
- return true
- }
-
// factory configuration has changed
return cfg.Relay != new.Relay || cfg.RelayTimeout != new.RelayTimeout
}
-// makeCommands returns new command provider based on configured options.
-func (cfg *ServerConfig) makeCommand() (func() *exec.Cmd, error) {
- var (
- err error
- u *user.User
- g *user.Group
- crd *syscall.Credential
- cmd = strings.Split(cfg.Command, " ")
- )
-
- if cfg.User != "" {
- if u, err = resolveUser(cfg.User); err != nil {
- return nil, err
- }
- }
-
- if cfg.Group != "" {
- if g, err = resolveGroup(cfg.Group); err != nil {
- return nil, err
- }
- }
-
- if u != nil || g != nil {
- crd = &syscall.Credential{}
-
- if u != nil {
- uid, err := strconv.ParseUint(u.Uid, 10, 32)
- if err != nil {
- return nil, err
- }
-
- crd.Uid = uint32(uid)
- }
-
- if g != nil {
- gid, err := strconv.ParseUint(g.Gid, 10, 32)
- if err != nil {
- return nil, err
- }
-
- crd.Gid = uint32(gid)
- }
- }
-
- return func() *exec.Cmd {
- cmd := exec.Command(cmd[0], cmd[1:]...)
- if crd != nil {
- cmd.SysProcAttr = &syscall.SysProcAttr{Credential: crd}
- }
-
- return cmd
- }, nil
-}
-
// makeFactory creates and connects new factory instance based on given parameters.
func (cfg *ServerConfig) makeFactory() (Factory, error) {
if cfg.Relay == "pipes" || cfg.Relay == "pipe" {
diff --git a/server_config_test.go b/server_config_test.go
index 42d2fec4..e3ef6ec0 100644
--- a/server_config_test.go
+++ b/server_config_test.go
@@ -3,9 +3,7 @@ package roadrunner
import (
"testing"
"github.com/stretchr/testify/assert"
- "os/user"
"runtime"
- "strconv"
)
func Test_ServerConfig_PipeFactory(t *testing.T) {
@@ -50,6 +48,10 @@ func Test_ServerConfig_SocketFactory(t *testing.T) {
}
func Test_ServerConfig_UnixSocketFactory(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ t.Skip("not supported on " + runtime.GOOS)
+ }
+
cfg := &ServerConfig{Relay: "unix://unix.sock"}
f, err := cfg.makeFactory()
defer f.Close()
@@ -61,41 +63,13 @@ func Test_ServerConfig_UnixSocketFactory(t *testing.T) {
}
func Test_ServerConfig_ErrorFactory(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ t.Skip("not supported on " + runtime.GOOS)
+ }
+
cfg := &ServerConfig{Relay: "uni:unix.sock"}
f, err := cfg.makeFactory()
assert.Nil(t, f)
assert.Error(t, err)
assert.Equal(t, "invalid relay DSN (pipes, tcp://:6001, unix://rr.sock)", err.Error())
}
-
-func Test_ServerConfig_Cmd(t *testing.T) {
- cfg := &ServerConfig{
- Command: "php php-src/tests/client.php pipes",
- }
-
- cmd, err := cfg.makeCommand()
- assert.NoError(t, err)
- assert.NotNil(t, cmd)
-}
-
-func Test_ServerConfig_Cmd_Credentials(t *testing.T) {
- if runtime.GOOS == "windows" {
- t.Skip("not supported on " + runtime.GOOS)
- }
-
- u, err := user.Current()
- assert.NoError(t, err)
-
- cfg := &ServerConfig{
- Command: "php php-src/tests/client.php pipes",
- User: u.Username,
- Group: u.Gid,
- }
-
- cmd, err := cfg.makeCommand()
- assert.NoError(t, err)
- assert.NotNil(t, cmd)
-
- assert.Equal(t, u.Uid, strconv.Itoa(int(cmd().SysProcAttr.Credential.Uid)))
- assert.Equal(t, u.Gid, strconv.Itoa(int(cmd().SysProcAttr.Credential.Gid)))
-}
diff --git a/server_test.go b/server_test.go
index cfc75265..6cc07c4d 100644
--- a/server_test.go
+++ b/server_test.go
@@ -5,18 +5,20 @@ import (
"github.com/stretchr/testify/assert"
"runtime"
"time"
+ "os/exec"
)
func TestServer_PipesEcho(t *testing.T) {
- srv := NewServer(&ServerConfig{
- Command: "php php-src/tests/client.php echo pipes",
- Relay: "pipes",
- Pool: &Config{
- NumWorkers: uint64(runtime.NumCPU()),
- AllocateTimeout: time.Second,
- DestroyTimeout: time.Second,
- },
- }, nil)
+ srv := NewServer(
+ func() *exec.Cmd { return exec.Command("php", "php-src/tests/client.php", "echo", "pipes") },
+ &ServerConfig{
+ Relay: "pipes",
+ Pool: Config{
+ NumWorkers: uint64(runtime.NumCPU()),
+ AllocateTimeout: time.Second,
+ DestroyTimeout: time.Second,
+ },
+ })
defer srv.Stop()
assert.NoError(t, srv.Start())
@@ -32,16 +34,17 @@ func TestServer_PipesEcho(t *testing.T) {
}
func TestServer_SocketEcho(t *testing.T) {
- srv := NewServer(&ServerConfig{
- Command: "php php-src/tests/client.php echo tcp",
- Relay: "tcp://:9007",
- RelayTimeout: 10 * time.Second,
- Pool: &Config{
- NumWorkers: uint64(runtime.NumCPU()),
- AllocateTimeout: time.Second,
- DestroyTimeout: time.Second,
- },
- }, nil)
+ srv := NewServer(
+ func() *exec.Cmd { return exec.Command("php", "php-src/tests/client.php", "echo", "tcp") },
+ &ServerConfig{
+ Relay: "tcp://:9007",
+ RelayTimeout: 10 * time.Second,
+ Pool: Config{
+ NumWorkers: uint64(runtime.NumCPU()),
+ AllocateTimeout: time.Second,
+ DestroyTimeout: time.Second,
+ },
+ })
defer srv.Stop()
assert.NoError(t, srv.Start())
@@ -57,24 +60,24 @@ func TestServer_SocketEcho(t *testing.T) {
}
func TestServer_Reconfigure(t *testing.T) {
- srv := NewServer(&ServerConfig{
- Command: "php php-src/tests/client.php echo pipes",
- Relay: "pipes",
- Pool: &Config{
- NumWorkers: 1,
- AllocateTimeout: time.Second,
- DestroyTimeout: time.Second,
- },
- }, nil)
+ srv := NewServer(
+ func() *exec.Cmd { return exec.Command("php", "php-src/tests/client.php", "echo", "pipes") },
+ &ServerConfig{
+ Relay: "pipes",
+ Pool: Config{
+ NumWorkers: 1,
+ AllocateTimeout: time.Second,
+ DestroyTimeout: time.Second,
+ },
+ })
defer srv.Stop()
assert.NoError(t, srv.Start())
assert.Len(t, srv.Workers(), 1)
err := srv.Reconfigure(&ServerConfig{
- Command: "php php-src/tests/client.php echo pipes",
- Relay: "pipes",
- Pool: &Config{
+ Relay: "pipes",
+ Pool: Config{
NumWorkers: 2,
AllocateTimeout: time.Second,
DestroyTimeout: time.Second,
@@ -86,15 +89,16 @@ func TestServer_Reconfigure(t *testing.T) {
}
func TestServer_Reset(t *testing.T) {
- srv := NewServer(&ServerConfig{
- Command: "php php-src/tests/client.php echo pipes",
- Relay: "pipes",
- Pool: &Config{
- NumWorkers: 1,
- AllocateTimeout: time.Second,
- DestroyTimeout: time.Second,
- },
- }, nil)
+ srv := NewServer(
+ func() *exec.Cmd { return exec.Command("php", "php-src/tests/client.php", "echo", "pipes") },
+ &ServerConfig{
+ Relay: "pipes",
+ Pool: Config{
+ NumWorkers: 1,
+ AllocateTimeout: time.Second,
+ DestroyTimeout: time.Second,
+ },
+ })
defer srv.Stop()
assert.NoError(t, srv.Start())
diff --git a/user.go b/user.go
deleted file mode 100644
index 1d47b5fb..00000000
--- a/user.go
+++ /dev/null
@@ -1,31 +0,0 @@
-package roadrunner
-
-import (
- "os/user"
- "fmt"
-)
-
-// resolveUser attempt to find system user by it's name or uid.
-func resolveUser(u string) (usr *user.User, err error) {
- usr, err = user.LookupId(u)
- if usr != nil {
- return usr, nil
- }
-
- return user.Lookup(u)
-}
-
-// resolveUser attempt to find system group by it's name or uid.
-func resolveGroup(g string) (grp *user.Group, err error) {
- grp, err = user.LookupGroupId(g)
- if grp != nil && grp.Name != "nogroup" {
- return grp, nil
- }
-
- grp, err = user.LookupGroup(g)
- if grp != nil && grp.Name != "nogroup" {
- return grp, nil
- }
-
- return nil, fmt.Errorf("no such group %s", g)
-}
diff --git a/user_test.go b/user_test.go
deleted file mode 100644
index 1b945e3c..00000000
--- a/user_test.go
+++ /dev/null
@@ -1,76 +0,0 @@
-package roadrunner
-
-import (
- "testing"
- "runtime"
- "github.com/stretchr/testify/assert"
- "os/user"
-)
-
-func Test_ResolveUser_Error(t *testing.T) {
- if runtime.GOOS == "windows" {
- t.Skip("not supported on " + runtime.GOOS)
- }
-
- u, err := resolveUser("-1")
- assert.Nil(t, u)
- assert.Error(t, err)
-
- u, err = resolveUser("random-user")
- assert.Nil(t, u)
- assert.Error(t, err)
-}
-
-func Test_ResolveUser(t *testing.T) {
- if runtime.GOOS == "windows" {
- t.Skip("not supported on " + runtime.GOOS)
- }
-
- current, err := user.Current()
- assert.NotNil(t, current)
- assert.NoError(t, err)
-
- u, err := resolveUser(current.Uid)
- assert.NoError(t, err)
- assert.NotNil(t, u)
- assert.Equal(t, current.Uid, u.Uid)
-
- u, err = resolveUser(current.Username)
- assert.NoError(t, err)
- assert.NotNil(t, u)
- assert.Equal(t, current.Uid, u.Uid)
-}
-
-func Test_ResolveGroup_Error(t *testing.T) {
- if runtime.GOOS == "windows" {
- t.Skip("not supported on " + runtime.GOOS)
- }
-
- g, err := resolveGroup("-1")
- assert.Nil(t, g)
- assert.Error(t, err)
-
- g, err = resolveGroup("random-group")
- assert.Nil(t, g)
- assert.Error(t, err)
-}
-
-func Test_ResolveGroup(t *testing.T) {
- if runtime.GOOS == "windows" {
- t.Skip("not supported on " + runtime.GOOS)
- }
-
- current, err := user.Current()
- assert.NotNil(t, current)
- assert.NoError(t, err)
-
- g, err := resolveGroup(current.Gid)
- assert.NoError(t, err)
- assert.NotNil(t, g)
- assert.Equal(t, current.Gid, g.Gid)
-
- g2, err := resolveGroup(g.Name)
- assert.NoError(t, err)
- assert.NotNil(t, g2)
- assert.Equal(t, g2.Gid, g.Gid)
-}