Skip to content

Commit

Permalink
Merge pull request #183 from vania-pooh/master
Browse files Browse the repository at this point in the history
Added ability to override --userns flag (fixes #182)
  • Loading branch information
aandryashin authored Sep 18, 2018
2 parents 744c776 + e398dc8 commit 7dca490
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 21 deletions.
3 changes: 3 additions & 0 deletions cmd/selenoid.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ var (
browserEnv string
port uint16
uiPort uint16
userNS string
)

func init() {
Expand Down Expand Up @@ -155,6 +156,7 @@ func initFlags() {
} {
c.Flags().StringVarP(&args, "args", "g", "", "additional service arguments (e.g. \"-limit 5\")")
c.Flags().StringVarP(&env, "env", "e", "", "override service environment variables (e.g. \"KEY1=value1 KEY2=value2\")")
c.Flags().StringVarP(&userNS, "userns", "", "", "override user namespace, similarly to \"docker run --userns host ...\" (Docker only)")
}
}

Expand All @@ -174,6 +176,7 @@ func createLifecycle(configDir string, port uint16) (*selenoid.Lifecycle, error)
RegistryUrl: registry,
Tmpfs: tmpfs,
VNC: vnc,
UserNS: userNS,

BrowsersJsonUrl: browsersJSONUrl,
OS: operatingSystem,
Expand Down
7 changes: 5 additions & 2 deletions selenoid/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"path/filepath"

"github.com/fatih/color"
colorable "github.com/mattn/go-colorable"
"github.com/mattn/go-colorable"
)

type StatusProvider interface {
Expand Down Expand Up @@ -118,8 +118,11 @@ type PortAware struct {
Port int
}

type UserNSAware struct {
UserNS string
}

const (
GgrUIDefaultPort = 8888
SelenoidDefaultPort = 4444
SelenoidUIDefaultPort = 8080
DefaultRegistryUrl = "https://registry.hub.docker.com"
Expand Down
90 changes: 71 additions & 19 deletions selenoid/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ type DockerConfigurator struct {
EnvAware
BrowserEnvAware
PortAware
UserNSAware
LastVersions int
Pull bool
RegistryUrl string
Expand All @@ -94,6 +95,7 @@ func NewDockerConfigurator(config *LifecycleConfig) (*DockerConfigurator, error)
EnvAware: EnvAware{Env: config.Env},
BrowserEnvAware: BrowserEnvAware{BrowserEnv: config.BrowserEnv},
PortAware: PortAware{Port: config.Port},
UserNSAware: UserNSAware{UserNS: config.UserNS},
RegistryUrl: config.RegistryUrl,
LastVersions: config.LastVersions,
Tmpfs: config.Tmpfs,
Expand Down Expand Up @@ -617,7 +619,12 @@ func (c *DockerConfigurator) PrintArgs() error {
if image == nil {
return errors.New("Selenoid image is not downloaded: this is probably a bug")
}
return c.startContainer("", image, 0, 0, []string{}, []string{}, []string{"--help"}, []string{}, true)
cfg := &containerConfig{
Image: image,
Cmd: []string{"--help"},
PrintLogs: true,
}
return c.startContainer(cfg)
}

const (
Expand Down Expand Up @@ -667,7 +674,17 @@ func (c *DockerConfigurator) Start() error {
if !strings.Contains(c.Env, "OVERRIDE_VIDEO_OUTPUT_DIR") {
overrideEnv = append(overrideEnv, fmt.Sprintf("OVERRIDE_VIDEO_OUTPUT_DIR=%s", videoConfigDir))
}
return c.startContainer(selenoidContainerName, image, c.Port, SelenoidDefaultPort, volumes, []string{}, cmd, overrideEnv, false)
cfg := &containerConfig{
Name: selenoidContainerName,
Image: image,
HostPort: c.Port,
ServicePort: SelenoidDefaultPort,
Volumes: volumes,
Cmd: cmd,
OverrideEnv: overrideEnv,
UserNS: c.UserNS,
}
return c.startContainer(cfg)
}

func (c *DockerConfigurator) isDockerForWindows() bool {
Expand Down Expand Up @@ -737,7 +754,12 @@ func (c *DockerConfigurator) PrintUIArgs() error {
if image == nil {
return errors.New("Selenoid UI image is not downloaded: this is probably a bug")
}
return c.startContainer("", image, 0, 0, []string{}, []string{}, []string{"--help"}, []string{}, true)
cfg := &containerConfig{
Image: image,
Cmd: []string{"--help"},
PrintLogs: true,
}
return c.startContainer(cfg)
}

func (c *DockerConfigurator) StartUI() error {
Expand Down Expand Up @@ -775,7 +797,17 @@ containers:
}

overrideEnv := strings.Fields(c.Env)
return c.startContainer(selenoidUIContainerName, image, c.Port, SelenoidUIDefaultPort, []string{}, links, cmd, overrideEnv, false)
cfg := &containerConfig{
Name: selenoidUIContainerName,
Image: image,
HostPort: c.Port,
ServicePort: SelenoidUIDefaultPort,
Links: links,
Cmd: cmd,
OverrideEnv: overrideEnv,
UserNS: c.UserNS,
}
return c.startContainer(cfg)
}

func validateEnviron(envs []string) []string {
Expand All @@ -789,53 +821,73 @@ func validateEnviron(envs []string) []string {
return validEnv
}

func (c *DockerConfigurator) startContainer(name string, image *types.ImageSummary, hostPort int, servicePort int, volumes []string, links []string, cmd []string, envOverride []string, printLogs bool) error {
type containerConfig struct {
Name string
Image *types.ImageSummary
HostPort int
ServicePort int
Volumes []string
Links []string
Cmd []string
OverrideEnv []string
UserNS string
PrintLogs bool
}

func (c *DockerConfigurator) startContainer(cfg *containerConfig) error {
ctx := context.Background()
env := validateEnviron(os.Environ())
env = append(env, fmt.Sprintf("TZ=%s", time.Local))
if len(envOverride) > 0 {
env = envOverride
if len(cfg.OverrideEnv) > 0 {
env = cfg.OverrideEnv
}
if !contains(env, dockerApiVersion) {
env = append(env, fmt.Sprintf("%s=%s", dockerApiVersion, c.docker.ClientVersion()))
}
servicePortString := strconv.Itoa(servicePort)
servicePortString := strconv.Itoa(cfg.ServicePort)
port, err := nat.NewPort("tcp", servicePortString)
if err != nil {
return fmt.Errorf("failed to init port: %v", err)
}
containerConfig := container.Config{
Hostname: "localhost",
Image: image.RepoTags[0],
Image: cfg.Image.RepoTags[0],
Env: env,
}
if servicePort > 0 {
if cfg.ServicePort > 0 {
containerConfig.ExposedPorts = map[nat.Port]struct{}{port: {}}
}
if len(cmd) > 0 {
containerConfig.Cmd = strslice.StrSlice(cmd)
if len(cfg.Cmd) > 0 {
containerConfig.Cmd = strslice.StrSlice(cfg.Cmd)
}
hostConfig := container.HostConfig{
Binds: volumes,
Links: links,
Binds: cfg.Volumes,
Links: cfg.Links,
}
if cfg.UserNS != "" {
mode := container.UsernsMode(cfg.UserNS)
if !mode.Valid() {
return fmt.Errorf("invalid userns value: %s", cfg.UserNS)
}
hostConfig.UsernsMode = mode
}
if printLogs {
if cfg.PrintLogs {
containerConfig.Tty = true
} else {
hostConfig.RestartPolicy = container.RestartPolicy{
Name: "always",
}
}
if hostPort > 0 && servicePort > 0 {
hostPortString := strconv.Itoa(hostPort)
if cfg.HostPort > 0 && cfg.ServicePort > 0 {
hostPortString := strconv.Itoa(cfg.HostPort)
portBindings := nat.PortMap{}
portBindings[port] = []nat.PortBinding{{HostIP: "0.0.0.0", HostPort: hostPortString}}
hostConfig.PortBindings = portBindings
}
ctr, err := c.docker.ContainerCreate(ctx,
&containerConfig,
&hostConfig,
&network.NetworkingConfig{}, name)
&network.NetworkingConfig{}, cfg.Name)
if err != nil {
return fmt.Errorf("failed to create container: %v", err)
}
Expand All @@ -844,7 +896,7 @@ func (c *DockerConfigurator) startContainer(name string, image *types.ImageSumma
c.removeContainer(ctr.ID)
return fmt.Errorf("failed to start container: %v", err)
}
if printLogs {
if cfg.PrintLogs {
defer c.removeContainer(ctr.ID)
r, err := c.docker.ContainerLogs(ctx, ctr.ID, types.ContainerLogsOptions{
ShowStdout: true,
Expand Down
1 change: 1 addition & 0 deletions selenoid/docker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ func TestStartStopContainer(t *testing.T) {
RegistryUrl: mockDockerServer.URL,
Port: SelenoidDefaultPort,
Version: Latest,
UserNS: "host",
})
AssertThat(t, err, Is{nil})
AssertThat(t, c.IsRunning(), Is{true})
Expand Down
1 change: 1 addition & 0 deletions selenoid/lifecycle.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type LifecycleConfig struct {
RegistryUrl string
Tmpfs int
VNC bool
UserNS string

// Drivers specific
BrowsersJsonUrl string
Expand Down

0 comments on commit 7dca490

Please sign in to comment.