summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWolfy-J <[email protected]>2018-06-06 13:39:07 +0300
committerWolfy-J <[email protected]>2018-06-06 13:39:07 +0300
commit7067d593f243e86a54f4ffd87a06c744e5636e07 (patch)
tree83ba4ab9503059e2383fe40a04be6f1e7d2b9f2f
parentb49a888579be9dfc33069d168083c54fb354e24c (diff)
command factory
-rw-r--r--cmd/_____/factory.go37
-rw-r--r--server_config.go64
-rw-r--r--server_config_test.go10
-rw-r--r--user.go31
-rw-r--r--user_test.go81
5 files changed, 180 insertions, 43 deletions
diff --git a/cmd/_____/factory.go b/cmd/_____/factory.go
deleted file mode 100644
index cee962e2..00000000
--- a/cmd/_____/factory.go
+++ /dev/null
@@ -1,37 +0,0 @@
-package _____
-
-import (
- "github.com/spiral/roadrunner"
- "os/exec"
- "strings"
- "time"
-)
-
-// todo: move out
-type PoolConfig struct {
- Command string
- Relay string
-
- Number uint64
- MaxJobs uint64
-
- Timeouts struct {
- Construct int
- Allocate int
- Destroy int
- }
-}
-
-func (f *PoolConfig) rrConfig() roadrunner.Config {
- return roadrunner.Config{
- NumWorkers: f.Number,
- MaxExecutions: f.MaxJobs,
- AllocateTimeout: time.Second * time.Duration(f.Timeouts.Allocate),
- DestroyTimeout: time.Second * time.Duration(f.Timeouts.Destroy),
- }
-}
-
-func (f *PoolConfig) cmd() func() *exec.Cmd {
- cmd := strings.Split(f.Command, " ")
- return func() *exec.Cmd { return exec.Command(cmd[0], cmd[1:]...) }
-}
diff --git a/server_config.go b/server_config.go
index 99eaa678..0a06d749 100644
--- a/server_config.go
+++ b/server_config.go
@@ -6,6 +6,9 @@ import (
"strings"
"time"
"os/exec"
+ "syscall"
+ "os/user"
+ "strconv"
)
const (
@@ -41,17 +44,66 @@ type ServerConfig struct {
Pool *Config
}
-func (f *ServerConfig) makeCommand() (func() *exec.Cmd, error) {
- return nil, nil
+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.Credential = crd
+ }
+
+ return cmd
+ }, nil
}
// makeFactory creates and connects new factory instance based on given parameters.
-func (f *ServerConfig) makeFactory() (Factory, error) {
- if f.Relay == "pipes" || f.Relay == "pipe" {
+func (cfg *ServerConfig) makeFactory() (Factory, error) {
+ if cfg.Relay == "pipes" || cfg.Relay == "pipe" {
return NewPipeFactory(), nil
}
- dsn := strings.Split(f.Relay, "://")
+ dsn := strings.Split(cfg.Relay, "://")
if len(dsn) != 2 {
return nil, errors.New("invalid relay DSN (pipes, tcp://:6001, unix://rr.sock)")
}
@@ -61,5 +113,5 @@ func (f *ServerConfig) makeFactory() (Factory, error) {
return nil, nil
}
- return NewSocketFactory(ln, time.Second*f.FactoryTimeout), nil
+ return NewSocketFactory(ln, time.Second*cfg.FactoryTimeout), nil
}
diff --git a/server_config_test.go b/server_config_test.go
index 667cfced..bd3ee76b 100644
--- a/server_config_test.go
+++ b/server_config_test.go
@@ -58,3 +58,13 @@ func Test_ServerConfig_ErrorFactory(t *testing.T) {
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)
+}
diff --git a/user.go b/user.go
new file mode 100644
index 00000000..1d47b5fb
--- /dev/null
+++ b/user.go
@@ -0,0 +1,31 @@
+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
new file mode 100644
index 00000000..3a9f6da9
--- /dev/null
+++ b/user_test.go
@@ -0,0 +1,81 @@
+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.Name)
+ 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)
+}