From 6576e3961088b6f7e755f7e4bff25f1f463e0053 Mon Sep 17 00:00:00 2001 From: Ivan Krutov Date: Mon, 3 Jul 2017 18:35:32 +0300 Subject: [PATCH] Added --env and --browser-env flags (fixes #45) --- cmd/selenoid.go | 26 +++++++++++++++++++------- selenoid/base.go | 8 ++++++++ selenoid/docker.go | 19 ++++++++++++++++--- selenoid/docker_test.go | 13 +++++++++---- selenoid/drivers.go | 30 +++++++++++++++++++++--------- selenoid/drivers_test.go | 7 ++++++- selenoid/lifecycle.go | 16 +++++++++------- vendor/vendor.json | 12 ++++++------ 8 files changed, 94 insertions(+), 37 deletions(-) diff --git a/cmd/selenoid.go b/cmd/selenoid.go index 170662e..5d7708b 100644 --- a/cmd/selenoid.go +++ b/cmd/selenoid.go @@ -28,6 +28,8 @@ var ( vnc bool force bool args string + env string + browserEnv string ) func init() { @@ -102,10 +104,17 @@ func initFlags() { selenoidUpdateCmd, } { c.Flags().StringVarP(&version, "version", "v", selenoid.Latest, "desired version; default is latest release") + c.Flags().StringVarP(®istry, "registry", "r", registryUrl, "Docker registry to use") + } + for _, c := range []*cobra.Command{ + selenoidConfigureCmd, + selenoidStartCmd, + selenoidUpdateCmd, + } { c.Flags().StringVarP(&browsers, "browsers", "b", "", "comma separated list of browser names to process") + c.Flags().StringVarP(&browserEnv, "browser-env", "w", "", "override container or driver environment variables (e.g. \"KEY1=value1 KEY2=value2\")") c.Flags().StringVarP(&browsersJSONUrl, "browsers-json", "j", defaultBrowsersJsonURL, "browsers JSON data URL (in most cases never need to be set manually)") c.Flags().BoolVarP(&skipDownload, "no-download", "n", false, "only output config file without downloading images or drivers") - c.Flags().StringVarP(®istry, "registry", "r", registryUrl, "Docker registry to use") c.Flags().IntVarP(&lastVersions, "last-versions", "l", 2, "process only last N versions (Docker only)") c.Flags().IntVarP(&tmpfs, "tmpfs", "t", 0, "add tmpfs volume sized in megabytes (Docker only)") c.Flags().BoolVarP(&vnc, "vnc", "s", false, "download containers with VNC support (Docker only)") @@ -126,17 +135,20 @@ func initFlags() { selenoidUpdateUICmd, } { 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\")") } } func createLifecycle() (*selenoid.Lifecycle, error) { config := selenoid.LifecycleConfig{ - Quiet: quiet, - Force: force, - ConfigDir: configDir, - Browsers: browsers, - Download: !skipDownload, - Args: args, + Quiet: quiet, + Force: force, + ConfigDir: configDir, + Browsers: browsers, + BrowserEnv: browserEnv, + Download: !skipDownload, + Args: args, + Env: env, LastVersions: lastVersions, RegistryUrl: registry, diff --git a/selenoid/base.go b/selenoid/base.go index 17be356..6b0bcf0 100644 --- a/selenoid/base.go +++ b/selenoid/base.go @@ -72,3 +72,11 @@ type RequestedBrowsersAware struct { type ArgsAware struct { Args string } + +type EnvAware struct { + Env string +} + +type BrowserEnvAware struct { + BrowserEnv string +} diff --git a/selenoid/docker.go b/selenoid/docker.go index 80818d0..9e115ce 100644 --- a/selenoid/docker.go +++ b/selenoid/docker.go @@ -49,6 +49,8 @@ type DockerConfigurator struct { DownloadAware RequestedBrowsersAware ArgsAware + EnvAware + BrowserEnvAware LastVersions int Pull bool RegistryUrl string @@ -66,6 +68,8 @@ func NewDockerConfigurator(config *LifecycleConfig) (*DockerConfigurator, error) DownloadAware: DownloadAware{DownloadNeeded: config.Download}, RequestedBrowsersAware: RequestedBrowsersAware{Browsers: config.Browsers}, ArgsAware: ArgsAware{Args: config.Args}, + EnvAware: EnvAware{Env: config.Env}, + BrowserEnvAware: BrowserEnvAware{BrowserEnv: config.BrowserEnv}, RegistryUrl: config.RegistryUrl, LastVersions: config.LastVersions, Tmpfs: config.Tmpfs, @@ -318,6 +322,10 @@ func (c *DockerConfigurator) createVersions(browserName string, image string, ta tmpfs["/tmp"] = fmt.Sprintf("size=%dm", c.Tmpfs) browser.Tmpfs = tmpfs } + browserEnv := strings.Fields(c.BrowserEnv) + if len(browserEnv) > 0 { + browser.Env = browserEnv + } versions.Versions[version] = browser } return versions @@ -453,7 +461,8 @@ func (c *DockerConfigurator) Start() error { volumes = append(volumes, fmt.Sprintf("%s:%s", dockerSocket, dockerSocket)) } - return c.startContainer(selenoidContainerName, image, selenoidContainerPort, volumes, []string{}, strings.Fields(c.Args)) + overrideEnv := strings.Fields(c.Env) + return c.startContainer(selenoidContainerName, image, selenoidContainerPort, volumes, []string{}, strings.Fields(c.Args), overrideEnv) } func (c *DockerConfigurator) StartUI() error { @@ -470,12 +479,16 @@ func (c *DockerConfigurator) StartUI() error { cmd = overrideCmd } - return c.startContainer(selenoidUIContainerName, image, selenoidUIContainerPort, []string{}, links, cmd) + overrideEnv := strings.Fields(c.Env) + return c.startContainer(selenoidUIContainerName, image, selenoidUIContainerPort, []string{}, links, cmd, overrideEnv) } -func (c *DockerConfigurator) startContainer(name string, image *types.ImageSummary, forwardedPort int, volumes []string, links []string, cmd []string) error { +func (c *DockerConfigurator) startContainer(name string, image *types.ImageSummary, forwardedPort int, volumes []string, links []string, cmd []string, envOverride []string) error { env := os.Environ() env = append(env, fmt.Sprintf("TZ=%s", time.Local)) + if len(envOverride) > 0 { + env = envOverride + } portString := strconv.Itoa(forwardedPort) port, err := nat.NewPort("tcp", portString) if err != nil { diff --git a/selenoid/docker_test.go b/selenoid/docker_test.go index c83d7b1..253705f 100644 --- a/selenoid/docker_test.go +++ b/selenoid/docker_test.go @@ -243,6 +243,8 @@ func testConfigure(t *testing.T, download bool) { Browsers: "firefox,opera", Args: "-limit 42", VNC: true, + Env: testEnv, + BrowserEnv: testEnv, } c, err := NewDockerConfigurator(&lcConfig) AssertThat(t, err, Is{nil}) @@ -268,28 +270,31 @@ func testConfigure(t *testing.T, download bool) { Port: "4444", Path: "/wd/hub", Tmpfs: tmpfsMap, + Env: []string{testEnv}, } correctFFBrowsers["45.0"] = &config.Browser{ Image: "selenoid/vnc:firefox_45.0", Port: "4444", Path: "/wd/hub", Tmpfs: tmpfsMap, + Env: []string{testEnv}, } AssertThat(t, firefoxVersions, EqualTo{config.Versions{ Default: "46.0", Versions: correctFFBrowsers, }}) - operaVersions, hasPhantomjsKey := cfg["opera"] - AssertThat(t, hasPhantomjsKey, Is{true}) + operaVersions, hasOperaKey := cfg["opera"] + AssertThat(t, hasOperaKey, Is{true}) AssertThat(t, operaVersions, Is{Not{nil}}) AssertThat(t, operaVersions.Default, EqualTo{"44.0"}) - correctPhantomjsBrowsers := make(map[string]*config.Browser) - correctPhantomjsBrowsers["2.1.1"] = &config.Browser{ + correctOperaBrowsers := make(map[string]*config.Browser) + correctOperaBrowsers["2.1.1"] = &config.Browser{ Image: "selenoid/opera:44.0", Port: "4444", Tmpfs: tmpfsMap, + Env: []string{testEnv}, } }) } diff --git a/selenoid/drivers.go b/selenoid/drivers.go index 2a03b19..8b5f648 100644 --- a/selenoid/drivers.go +++ b/selenoid/drivers.go @@ -63,6 +63,8 @@ type DriversConfigurator struct { VersionAware DownloadAware ArgsAware + EnvAware + BrowserEnvAware RequestedBrowsersAware Browsers string BrowsersJsonUrl string @@ -78,6 +80,8 @@ func NewDriversConfigurator(config *LifecycleConfig) *DriversConfigurator { ConfigDirAware: ConfigDirAware{ConfigDir: config.ConfigDir}, VersionAware: VersionAware{Version: config.Version}, ArgsAware: ArgsAware{Args: config.Args}, + EnvAware: EnvAware{Env: config.Env}, + BrowserEnvAware: BrowserEnvAware{BrowserEnv: config.BrowserEnv}, DownloadAware: DownloadAware{DownloadNeeded: config.Download}, RequestedBrowsersAware: RequestedBrowsersAware{Browsers: config.Browsers}, BrowsersJsonUrl: config.BrowsersJsonUrl, @@ -272,7 +276,7 @@ func (d *DriversConfigurator) Configure() (*SelenoidConfig, error) { return nil, fmt.Errorf("failed to create output directory: %v\n", err) } downloadedDrivers := d.downloadDrivers(browsers, d.ConfigDir) - cfg := generateConfig(downloadedDrivers) + cfg := d.generateConfig(downloadedDrivers) data, err := json.MarshalIndent(cfg, "", " ") if err != nil { return &cfg, fmt.Errorf("failed to marshal json: %v\n", err) @@ -280,17 +284,22 @@ func (d *DriversConfigurator) Configure() (*SelenoidConfig, error) { return &cfg, ioutil.WriteFile(getSelenoidConfigPath(d.ConfigDir), data, 0644) } -func generateConfig(downloadedDrivers []downloadedDriver) SelenoidConfig { +func (d *DriversConfigurator) generateConfig(downloadedDrivers []downloadedDriver) SelenoidConfig { browsers := make(SelenoidConfig) for _, dd := range downloadedDrivers { cmd := strings.Fields(dd.Command) + browser := &config.Browser{ + Image: cmd, + Path: "/", + } + browserEnv := strings.Fields(d.BrowserEnv) + if len(browserEnv) > 0 { + browser.Env = browserEnv + } versions := config.Versions{ Default: Latest, Versions: map[string]*config.Browser{ - Latest: { - Image: cmd, - Path: "/", - }, + Latest: browser, }, } browsers[dd.BrowserName] = versions @@ -545,12 +554,14 @@ func (d *DriversConfigurator) Start() error { if len(overrideArgs) > 0 { args = overrideArgs } - return runCommand(d.getSelenoidBinaryPath(), args) + env := strings.Fields(d.Env) + return runCommand(d.getSelenoidBinaryPath(), args, env) } func (d *DriversConfigurator) StartUI() error { args := strings.Fields(d.Args) - return runCommand(d.getSelenoidUIBinaryPath(), args) + env := strings.Fields(d.Env) + return runCommand(d.getSelenoidUIBinaryPath(), args, env) } var killFunc func(os.Process) error = func(p os.Process) error { @@ -605,11 +616,12 @@ func findProcesses(regex string) []os.Process { var execCommand = exec.Command -func runCommand(command string, args []string) error { +func runCommand(command string, args []string, env []string) error { cmd := execCommand(command, args...) cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr + cmd.Env = env return cmd.Start() } diff --git a/selenoid/drivers_test.go b/selenoid/drivers_test.go index 2fa195d..859dab1 100644 --- a/selenoid/drivers_test.go +++ b/selenoid/drivers_test.go @@ -22,6 +22,7 @@ const ( previousReleaseTag = "1.2.0" latestReleaseTag = "1.2.1" version = "version" + testEnv = "MYKEY=myvalue" ) var ( @@ -148,6 +149,9 @@ func TestConfigureDrivers(t *testing.T) { BrowsersJsonUrl: browsersJsonUrl, Download: true, Quiet: false, + Args: "-limit 42", + Env: testEnv, + BrowserEnv: testEnv, } configurator := NewDriversConfigurator(&lcConfig) AssertThat(t, configurator.IsConfigured(), Is{false}) @@ -167,6 +171,7 @@ func TestConfigureDrivers(t *testing.T) { Latest: { Image: []string{unpackedFirstFile}, Path: "/", + Env: []string{testEnv}, }, }, }, @@ -176,6 +181,7 @@ func TestConfigureDrivers(t *testing.T) { Latest: { Image: []string{unpackedSecondFile}, Path: "/", + Env: []string{testEnv}, }, }, }, @@ -390,7 +396,6 @@ func TestStartStopProcess(t *testing.T) { OS: runtime.GOOS, Arch: runtime.GOARCH, Version: Latest, - Args: "-limit 42", } configurator := NewDriversConfigurator(&lcConfig) AssertThat(t, configurator.IsRunning(), Is{true}) //This is probably true because test binary has name selenoid.test; no fake process is launched diff --git a/selenoid/lifecycle.go b/selenoid/lifecycle.go index 361dee6..efa430e 100644 --- a/selenoid/lifecycle.go +++ b/selenoid/lifecycle.go @@ -8,13 +8,15 @@ import ( ) type LifecycleConfig struct { - Quiet bool - Force bool - ConfigDir string - Browsers string - Download bool - Args string - Version string + Quiet bool + Force bool + ConfigDir string + Browsers string + BrowserEnv string + Download bool + Args string + Env string + Version string // Docker specific LastVersions int diff --git a/vendor/vendor.json b/vendor/vendor.json index e0142ab..3b248da 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -23,16 +23,16 @@ "revisionTime": "2016-07-29T13:19:23Z" }, { - "checksumSHA1": "RvHpyzTcdkjUkKBn0kmZ9irr724=", + "checksumSHA1": "RJ93VwpT4yuW2nQOfdi/ocfhoKc=", "path": "github.com/aerokube/selenoid/config", - "revision": "5b39d2bab8e58ae2d813b38f0a4305096b8ca92e", - "revisionTime": "2017-05-13T11:25:18Z" + "revision": "368bfbbfbc0ea07ec9f81f8ea5b1aabe38516cbd", + "revisionTime": "2017-07-03T10:52:49Z" }, { - "checksumSHA1": "Cq8PTDf6LLWGYm2Dwu/D3Nh0JqM=", + "checksumSHA1": "wwFIjzJhaV3fFP02UwrHAXFMNiE=", "path": "github.com/aerokube/selenoid/session", - "revision": "5b39d2bab8e58ae2d813b38f0a4305096b8ca92e", - "revisionTime": "2017-05-13T11:25:18Z" + "revision": "368bfbbfbc0ea07ec9f81f8ea5b1aabe38516cbd", + "revisionTime": "2017-07-03T10:52:49Z" }, { "checksumSHA1": "Nge8TFcb8UiM2yAHwIoV8qdFKy4=",