mirror of
https://github.com/kemko/nomad.git
synced 2026-01-07 10:55:42 +03:00
Run as user on mac
This commit is contained in:
@@ -3,6 +3,7 @@ package executor
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
@@ -16,6 +17,7 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
syslog "github.com/RackSec/srslog"
|
||||
"github.com/armon/circbuf"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/mitchellh/go-ps"
|
||||
@@ -774,3 +776,40 @@ func (e *UniversalExecutor) Signal(s os.Signal) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *UniversalExecutor) LaunchSyslogServer() (*SyslogServerState, error) {
|
||||
// Ensure the context has been set first
|
||||
if e.ctx == nil {
|
||||
return nil, fmt.Errorf("SetContext must be called before launching the Syslog Server")
|
||||
}
|
||||
|
||||
e.syslogChan = make(chan *logging.SyslogMessage, 2048)
|
||||
l, err := e.getListener(e.ctx.PortLowerBound, e.ctx.PortUpperBound)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
e.logger.Printf("[DEBUG] syslog-server: launching syslog server on addr: %v", l.Addr().String())
|
||||
if err := e.configureLoggers(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
e.syslogServer = logging.NewSyslogServer(l, e.syslogChan, e.logger)
|
||||
go e.syslogServer.Start()
|
||||
go e.collectLogs(e.lre, e.lro)
|
||||
syslogAddr := fmt.Sprintf("%s://%s", l.Addr().Network(), l.Addr().String())
|
||||
return &SyslogServerState{Addr: syslogAddr}, nil
|
||||
}
|
||||
|
||||
func (e *UniversalExecutor) collectLogs(we io.Writer, wo io.Writer) {
|
||||
for logParts := range e.syslogChan {
|
||||
// If the severity of the log line is err then we write to stderr
|
||||
// otherwise all messages go to stdout
|
||||
if logParts.Severity == syslog.LOG_ERR {
|
||||
e.lre.Write(logParts.Message)
|
||||
e.lre.Write([]byte{'\n'})
|
||||
} else {
|
||||
e.lro.Write(logParts.Message)
|
||||
e.lro.Write([]byte{'\n'})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// +build darwin dragonfly freebsd netbsd openbsd solaris windows
|
||||
// +build !linux
|
||||
|
||||
package executor
|
||||
|
||||
@@ -17,10 +17,6 @@ func (e *UniversalExecutor) removeChrootMounts() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *UniversalExecutor) runAs(userid string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *UniversalExecutor) applyLimits(pid int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -3,9 +3,7 @@ package executor
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
@@ -166,56 +164,6 @@ func (e *UniversalExecutor) Stats() (*cstructs.TaskResourceUsage, error) {
|
||||
return &taskResUsage, nil
|
||||
}
|
||||
|
||||
// runAs takes a user id as a string and looks up the user, and sets the command
|
||||
// to execute as that user.
|
||||
func (e *UniversalExecutor) runAs(userid string) error {
|
||||
u, err := user.Lookup(userid)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to identify user %v: %v", userid, err)
|
||||
}
|
||||
|
||||
// Get the groups the user is a part of
|
||||
gidStrings, err := u.GroupIds()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to lookup user's group membership: %v", err)
|
||||
}
|
||||
|
||||
gids := make([]uint32, len(gidStrings))
|
||||
for _, gidString := range gidStrings {
|
||||
u, err := strconv.Atoi(gidString)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to convert user's group to int %s: %v", gidString, err)
|
||||
}
|
||||
|
||||
gids = append(gids, uint32(u))
|
||||
}
|
||||
|
||||
// Convert the uid and gid
|
||||
uid, err := strconv.ParseUint(u.Uid, 10, 32)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to convert userid to uint32: %s", err)
|
||||
}
|
||||
gid, err := strconv.ParseUint(u.Gid, 10, 32)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to convert groupid to uint32: %s", err)
|
||||
}
|
||||
|
||||
// Set the command to run as that user and group.
|
||||
if e.cmd.SysProcAttr == nil {
|
||||
e.cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||
}
|
||||
if e.cmd.SysProcAttr.Credential == nil {
|
||||
e.cmd.SysProcAttr.Credential = &syscall.Credential{}
|
||||
}
|
||||
e.cmd.SysProcAttr.Credential.Uid = uint32(uid)
|
||||
e.cmd.SysProcAttr.Credential.Gid = uint32(gid)
|
||||
e.cmd.SysProcAttr.Credential.Groups = gids
|
||||
|
||||
e.logger.Printf("[DEBUG] executor: running as user:group %d:%d with group membership in %v", uid, gid, gids)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// configureChroot configures a chroot
|
||||
func (e *UniversalExecutor) configureChroot() error {
|
||||
if e.cmd.SysProcAttr == nil {
|
||||
|
||||
@@ -1,49 +1,60 @@
|
||||
// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
|
||||
// +build !windows
|
||||
|
||||
package executor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
syslog "github.com/RackSec/srslog"
|
||||
|
||||
"github.com/hashicorp/nomad/client/driver/logging"
|
||||
"os/user"
|
||||
"strconv"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func (e *UniversalExecutor) LaunchSyslogServer() (*SyslogServerState, error) {
|
||||
// Ensure the context has been set first
|
||||
if e.ctx == nil {
|
||||
return nil, fmt.Errorf("SetContext must be called before launching the Syslog Server")
|
||||
}
|
||||
|
||||
e.syslogChan = make(chan *logging.SyslogMessage, 2048)
|
||||
l, err := e.getListener(e.ctx.PortLowerBound, e.ctx.PortUpperBound)
|
||||
// runAs takes a user id as a string and looks up the user, and sets the command
|
||||
// to execute as that user.
|
||||
func (e *UniversalExecutor) runAs(userid string) error {
|
||||
u, err := user.Lookup(userid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
e.logger.Printf("[DEBUG] syslog-server: launching syslog server on addr: %v", l.Addr().String())
|
||||
if err := e.configureLoggers(); err != nil {
|
||||
return nil, err
|
||||
return fmt.Errorf("Failed to identify user %v: %v", userid, err)
|
||||
}
|
||||
|
||||
e.syslogServer = logging.NewSyslogServer(l, e.syslogChan, e.logger)
|
||||
go e.syslogServer.Start()
|
||||
go e.collectLogs(e.lre, e.lro)
|
||||
syslogAddr := fmt.Sprintf("%s://%s", l.Addr().Network(), l.Addr().String())
|
||||
return &SyslogServerState{Addr: syslogAddr}, nil
|
||||
}
|
||||
// Get the groups the user is a part of
|
||||
gidStrings, err := u.GroupIds()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to lookup user's group membership: %v", err)
|
||||
}
|
||||
|
||||
func (e *UniversalExecutor) collectLogs(we io.Writer, wo io.Writer) {
|
||||
for logParts := range e.syslogChan {
|
||||
// If the severity of the log line is err then we write to stderr
|
||||
// otherwise all messages go to stdout
|
||||
if logParts.Severity == syslog.LOG_ERR {
|
||||
e.lre.Write(logParts.Message)
|
||||
e.lre.Write([]byte{'\n'})
|
||||
} else {
|
||||
e.lro.Write(logParts.Message)
|
||||
e.lro.Write([]byte{'\n'})
|
||||
gids := make([]uint32, len(gidStrings))
|
||||
for _, gidString := range gidStrings {
|
||||
u, err := strconv.Atoi(gidString)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to convert user's group to int %s: %v", gidString, err)
|
||||
}
|
||||
|
||||
gids = append(gids, uint32(u))
|
||||
}
|
||||
|
||||
// Convert the uid and gid
|
||||
uid, err := strconv.ParseUint(u.Uid, 10, 32)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to convert userid to uint32: %s", err)
|
||||
}
|
||||
gid, err := strconv.ParseUint(u.Gid, 10, 32)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to convert groupid to uint32: %s", err)
|
||||
}
|
||||
|
||||
// Set the command to run as that user and group.
|
||||
if e.cmd.SysProcAttr == nil {
|
||||
e.cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||
}
|
||||
if e.cmd.SysProcAttr.Credential == nil {
|
||||
e.cmd.SysProcAttr.Credential = &syscall.Credential{}
|
||||
}
|
||||
e.cmd.SysProcAttr.Credential.Uid = uint32(uid)
|
||||
e.cmd.SysProcAttr.Credential.Gid = uint32(gid)
|
||||
e.cmd.SysProcAttr.Credential.Groups = gids
|
||||
|
||||
e.logger.Printf("[DEBUG] executor: running as user:group %d:%d with group membership in %v", uid, gid, gids)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -7,8 +7,6 @@ import (
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -260,45 +258,6 @@ func TestRawExecDriver_Start_Kill_Wait(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRawExecDriverUser(t *testing.T) {
|
||||
t.Parallel()
|
||||
if runtime.GOOS != "linux" {
|
||||
t.Skip("Linux only test")
|
||||
}
|
||||
task := &structs.Task{
|
||||
Name: "sleep",
|
||||
Driver: "raw_exec",
|
||||
User: "alice",
|
||||
Config: map[string]interface{}{
|
||||
"command": testtask.Path(),
|
||||
"args": []string{"sleep", "45s"},
|
||||
},
|
||||
LogConfig: &structs.LogConfig{
|
||||
MaxFiles: 10,
|
||||
MaxFileSizeMB: 10,
|
||||
},
|
||||
Resources: basicResources,
|
||||
}
|
||||
testtask.SetTaskEnv(task)
|
||||
|
||||
ctx := testDriverContexts(t, task)
|
||||
defer ctx.AllocDir.Destroy()
|
||||
d := NewRawExecDriver(ctx.DriverCtx)
|
||||
|
||||
if _, err := d.Prestart(ctx.ExecCtx, task); err != nil {
|
||||
t.Fatalf("prestart err: %v", err)
|
||||
}
|
||||
resp, err := d.Start(ctx.ExecCtx, task)
|
||||
if err == nil {
|
||||
resp.Handle.Kill()
|
||||
t.Fatalf("Should've failed")
|
||||
}
|
||||
msg := "unknown user alice"
|
||||
if !strings.Contains(err.Error(), msg) {
|
||||
t.Fatalf("Expecting '%v' in '%v'", msg, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRawExecDriver_HandlerExec(t *testing.T) {
|
||||
t.Parallel()
|
||||
task := &structs.Task{
|
||||
|
||||
@@ -10,10 +10,47 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/nomad/helper/testtask"
|
||||
"github.com/hashicorp/nomad/nomad/structs"
|
||||
"github.com/hashicorp/nomad/testutil"
|
||||
)
|
||||
|
||||
func TestRawExecDriver_User(t *testing.T) {
|
||||
t.Parallel()
|
||||
task := &structs.Task{
|
||||
Name: "sleep",
|
||||
Driver: "raw_exec",
|
||||
User: "alice",
|
||||
Config: map[string]interface{}{
|
||||
"command": testtask.Path(),
|
||||
"args": []string{"sleep", "45s"},
|
||||
},
|
||||
LogConfig: &structs.LogConfig{
|
||||
MaxFiles: 10,
|
||||
MaxFileSizeMB: 10,
|
||||
},
|
||||
Resources: basicResources,
|
||||
}
|
||||
testtask.SetTaskEnv(task)
|
||||
|
||||
ctx := testDriverContexts(t, task)
|
||||
defer ctx.AllocDir.Destroy()
|
||||
d := NewRawExecDriver(ctx.DriverCtx)
|
||||
|
||||
if _, err := d.Prestart(ctx.ExecCtx, task); err != nil {
|
||||
t.Fatalf("prestart err: %v", err)
|
||||
}
|
||||
resp, err := d.Start(ctx.ExecCtx, task)
|
||||
if err == nil {
|
||||
resp.Handle.Kill()
|
||||
t.Fatalf("Should've failed")
|
||||
}
|
||||
msg := "unknown user alice"
|
||||
if !strings.Contains(err.Error(), msg) {
|
||||
t.Fatalf("Expecting '%v' in '%v'", msg, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRawExecDriver_Signal(t *testing.T) {
|
||||
t.Parallel()
|
||||
task := &structs.Task{
|
||||
|
||||
Reference in New Issue
Block a user