func TestPackage(t *testing.T) { // At this stage, Juju only supports running the apiservers and database // on Ubuntu. If we end up officially supporting CentOS, then we should // make sure we run the tests there. if os.HostOS() != os.Ubuntu { t.Skipf("skipping tests on %v", os.HostOS()) } coretesting.MgoTestPackage(t) }
// validateUploadAllowed returns an error if an attempt to upload tools should // not be allowed. func validateUploadAllowed(env environs.Environ, toolsArch, toolsSeries *string, validator constraints.Validator) error { // Now check that the architecture and series for which we are setting up an // environment matches that from which we are bootstrapping. hostArch := arch.HostArch() // We can't build tools for a different architecture if one is specified. if toolsArch != nil && *toolsArch != hostArch { return fmt.Errorf("cannot use agent built for %q using a machine running on %q", *toolsArch, hostArch) } hostOS := jujuos.HostOS() if toolsSeries != nil { toolsSeriesOS, err := series.GetOSFromSeries(*toolsSeries) if err != nil { return errors.Trace(err) } if !toolsSeriesOS.EquivalentTo(hostOS) { return errors.Errorf("cannot use agent built for %q using a machine running %q", *toolsSeries, hostOS) } } // If no architecture is specified, ensure the target provider supports instances matching our architecture. if _, err := validator.Validate(constraints.Value{Arch: &hostArch}); err != nil { return errors.Errorf( "model %q of type %s does not support instances running on %q", env.Config().Name(), env.Config().Type(), hostArch, ) } return nil }
// NewPaths returns the set of filesystem paths that the supplied unit should // use, given the supplied root juju data directory path. func NewPaths(dataDir string, unitTag names.UnitTag) Paths { join := filepath.Join baseDir := join(dataDir, "agents", unitTag.String()) stateDir := join(baseDir, "state") socket := func(name string, abstract bool) string { if os.HostOS() == os.Windows { return fmt.Sprintf(`\\.\pipe\%s-%s`, unitTag, name) } path := join(baseDir, name+".socket") if abstract { path = "@" + path } return path } toolsDir := tools.ToolsDir(dataDir, unitTag.String()) return Paths{ ToolsDir: filepath.FromSlash(toolsDir), Runtime: RuntimePaths{ JujuRunSocket: socket("run", false), JujucServerSocket: socket("agent", true), }, State: StatePaths{ CharmDir: join(baseDir, "charm"), OperationsFile: join(stateDir, "uniter"), RelationsDir: join(stateDir, "relations"), BundlesDir: join(stateDir, "bundles"), DeployerDir: join(stateDir, "deployer"), StorageDir: join(stateDir, "storage"), MetricsSpoolDir: join(stateDir, "spool", "metrics"), }, } }
// NewWorker returns a worker that keeps track of // the machine's authorised ssh keys and ensures the // ~/.ssh/authorized_keys file is up to date. func NewWorker(st *keyupdater.State, agentConfig agent.Config) worker.Worker { if os.HostOS() == os.Windows { return worker.NewNoOpWorker() } kw := &keyupdaterWorker{st: st, tag: agentConfig.Tag().(names.MachineTag)} return worker.NewNotifyWorker(kw) }
func (runner *runner) runCharmHookWithLocation(hookName, charmLocation string) error { srv, err := runner.startJujucServer() if err != nil { return err } defer srv.Close() env, err := runner.context.HookVars(runner.paths) if err != nil { return errors.Trace(err) } if jujuos.HostOS() == jujuos.Windows { // TODO(fwereade): somehow consolidate with utils/exec? // We don't do this on the other code path, which uses exec.RunCommands, // because that already has handling for windows environment requirements. env = mergeWindowsEnvironment(env, os.Environ()) } debugctx := debug.NewHooksContext(runner.context.UnitName()) if session, _ := debugctx.FindSession(); session != nil && session.MatchHook(hookName) { logger.Infof("executing %s via debug-hooks", hookName) err = session.RunHook(hookName, runner.paths.GetCharmDir(), env) } else { err = runner.runCharmHook(hookName, env, charmLocation) } return runner.context.Flush(hookName, err) }
func syslogUserGroup() (string, string) { switch os.HostOS() { case os.CentOS: return "root", "adm" default: return "syslog", "syslog" } }
func syslogUser() string { switch jujuos.HostOS() { case jujuos.CentOS: return "root" default: return "syslog" } }
// appendProxyToCommands activates proxy settings on platforms // that support this feature via the command line. Currently this // will work on most GNU/Linux systems, but has no use in Windows // where the proxy settings are taken from the registry or from // application specific settings (proxy settings in firefox ignore // registry values on Windows). func (c *RunCommand) appendProxyToCommands() string { switch jujuos.HostOS() { case jujuos.Ubuntu: return `[ -f "/home/ubuntu/.juju-proxy" ] && . "/home/ubuntu/.juju-proxy"` + "\n" + c.commands default: return c.commands } }
func (w *proxyWorker) writeEnvironment() error { switch os.HostOS() { case os.Windows: return w.writeEnvironmentToRegistry() default: return w.writeEnvironmentFile() } }
// OSDependentEnvVars returns the OS-dependent environment variables that // should be set for a hook context. func OSDependentEnvVars(paths Paths) []string { switch jujuos.HostOS() { case jujuos.Windows: return windowsEnv(paths) case jujuos.Ubuntu: return ubuntuEnv(paths) case jujuos.CentOS: return centosEnv(paths) } return nil }
// removeJujudpass removes a file that is no longer used on versions >1.25 // The Jujud.pass file was created during cloud init before // so we know it's location for sure in case it exists func removeJujudpass(context Context) error { if os.HostOS() == os.Windows { fileLocation := "C:\\Juju\\Jujud.pass" if err := osRemove(fileLocation); err != nil { // Don't fail the step if we can't get rid of the old files. // We don't actually care if they still exist or not. logger.Warningf("can't delete old password file %q: %s", fileLocation, err) } } return nil }
// newRsyslogConfigWorker returns a worker.Worker that uses // WatchForRsyslogChanges and updates rsyslog configuration based // on changes. The worker will remove the configuration file // on teardown. func newRsyslogConfigWorker(st *apirsyslog.State, mode RsyslogMode, tag names.Tag, namespace string, stateServerAddrs []string, jujuConfigDir string) (worker.Worker, error) { if jujuos.HostOS() == jujuos.Windows && mode == RsyslogModeAccumulate { return worker.NewNoOpWorker(), nil } handler, err := newRsyslogConfigHandler(st, mode, tag, namespace, stateServerAddrs, jujuConfigDir) if err != nil { return nil, err } logger.Debugf("starting rsyslog worker mode %v for %q %q", mode, tag, namespace) return worker.NewNotifyWorker(handler), nil }
func (s *supportedSeriesSuite) TestSeriesVersion(c *gc.C) { // There is no distro-info on Windows or CentOS. if os.HostOS() != os.Ubuntu { c.Skip("This test is only relevant on Ubuntu.") } vers, err := series.SeriesVersion("precise") if err != nil && err.Error() == `invalid series "precise"` { c.Fatalf(`Unable to lookup series "precise", you may need to: apt-get install distro-info`) } c.Assert(err, jc.ErrorIsNil) c.Assert(vers, gc.Equals, "12.04") }
// addJujuRegKey tries to create the same key that is now created during cloudinit // on machines having version 1.25 or up // Since support for ACL's in golang is quite disastrous at the moment, and they're // not especially easy to use, this is done using the exact same steps used in cloudinit func addJujuRegKey(context Context) error { if os.HostOS() == os.Windows { cmds := cloudconfig.CreateJujuRegistryKeyCmds() _, err := execRunCommands(exec.RunParams{ Commands: strings.Join(cmds, "\n"), }) if err != nil { return errors.Annotate(err, "could not create juju registry key") } logger.Infof("created juju registry key at %s", osenv.JujuRegistryKey) return nil } return nil }
// locallyBuildableTools returns the list of tools that // can be built locally, for series of the same OS. func locallyBuildableTools() (buildable coretools.List) { for _, ser := range series.SupportedSeries() { if os, err := series.GetOSFromSeries(ser); err != nil || os != jujuos.HostOS() { continue } binary := version.Binary{ Number: version.Current.Number, Series: ser, Arch: arch.HostArch(), } // Increment the build number so we know it's a development build. binary.Build++ buildable = append(buildable, &coretools.Tools{Version: binary}) } return buildable }
func GetPackageManager() (s PackageManagerStruct, err error) { switch jujuos.HostOS() { case jujuos.CentOS: s.PackageManager = "yum" s.PackageQuery = "yum" s.RepositoryManager = "yum-config-manager --add-repo" case jujuos.Ubuntu: s.PackageManager = "apt-get" s.PackageQuery = "dpkg-query" s.RepositoryManager = "add-apt-repository" default: s.PackageManager = "apt-get" s.PackageQuery = "dpkg-query" s.RepositoryManager = "add-apt-repository" } return s, nil }
// hookCommand constructs an appropriate command to be passed to // exec.Command(). The exec package uses cmd.exe as default on windows. // cmd.exe does not know how to execute ps1 files by default, and // powershell needs a few flags to allow execution (-ExecutionPolicy) // and propagate error levels (-File). .cmd and .bat files can be run // directly. func hookCommand(hook string) []string { if jujuos.HostOS() != jujuos.Windows { // we are not running on windows, // just return the hook name return []string{hook} } if strings.HasSuffix(hook, ".ps1") { return []string{ "powershell.exe", "-NonInteractive", "-ExecutionPolicy", "RemoteSigned", "-File", hook, } } return []string{hook} }
func (s *RunTestSuite) runListenerForAgent(c *gc.C, agent string) { agentDir := filepath.Join(cmdutil.DataDir, "agents", agent) err := os.MkdirAll(agentDir, 0755) c.Assert(err, jc.ErrorIsNil) var socketPath string switch jujuos.HostOS() { case jujuos.Windows: socketPath = fmt.Sprintf(`\\.\pipe\%s-run`, agent) default: socketPath = fmt.Sprintf("%s/run.socket", agentDir) } listener, err := uniter.NewRunListener(&mockRunner{c}, socketPath) c.Assert(err, jc.ErrorIsNil) c.Assert(listener, gc.NotNil) s.AddCleanup(func(*gc.C) { c.Assert(listener.Close(), jc.ErrorIsNil) }) }
// NewWorker returns a worker that keeps track of // the machine's authorised ssh keys and ensures the // ~/.ssh/authorized_keys file is up to date. func NewWorker(st *keyupdater.State, agentConfig agent.Config) (worker.Worker, error) { machineTag, ok := agentConfig.Tag().(names.MachineTag) if !ok { return nil, errors.NotValidf("machine tag %v", agentConfig.Tag()) } if os.HostOS() == os.Windows { return worker.NewNoOpWorker(), nil } w, err := watcher.NewNotifyWorker(watcher.NotifyConfig{ Handler: &keyupdaterWorker{ st: st, tag: machineTag, }, }) if err != nil { return nil, errors.Trace(err) } return w, nil }
// locallyBuildableTools returns the list of tools that // can be built locally, for series of the same OS. func locallyBuildableTools(toolsSeries *string) (buildable coretools.List, _ version.Number) { buildNumber := jujuversion.Current // Increment the build number so we know it's a custom build. buildNumber.Build++ for _, ser := range series.SupportedSeries() { if os, err := series.GetOSFromSeries(ser); err != nil || !os.EquivalentTo(jujuos.HostOS()) { continue } if toolsSeries != nil && ser != *toolsSeries { continue } binary := version.Binary{ Number: buildNumber, Series: ser, Arch: arch.HostArch(), } buildable = append(buildable, &coretools.Tools{Version: binary}) } return buildable, buildNumber }
// searchHook will search, in order, hooks suffixed with extensions // in windowsSuffixOrder. As windows cares about extensions to determine // how to execute a file, we will allow several suffixes, with powershell // being default. func searchHook(charmDir, hook string) (string, error) { hookFile := filepath.Join(charmDir, hook) if jujuos.HostOS() != jujuos.Windows { // we are not running on windows, // there is no need to look for suffixed hooks return lookPath(hookFile) } for _, suffix := range windowsSuffixOrder { file := fmt.Sprintf("%s%s", hookFile, suffix) foundHook, err := lookPath(file) if err != nil { if context.IsMissingHookError(err) { // look for next suffix continue } return "", err } return foundHook, nil } return "", context.NewMissingHookError(hook) }
func (s *discoverySuite) TestDiscoverServiceLocalHost(c *gc.C) { var localInitSystem string var err error switch runtime.GOOS { case "windows": localInitSystem = service.InitSystemWindows case "linux": localInitSystem, err = service.VersionInitSystem(series.HostSeries()) } c.Assert(err, gc.IsNil) test := discoveryTest{ os: jujuos.HostOS(), series: series.HostSeries(), expected: localInitSystem, } test.disableVersionDiscovery(s) svc, err := service.DiscoverService(s.name, s.conf) c.Assert(err, jc.ErrorIsNil) test.checkService(c, svc, err, s.name, s.conf) }
// validateUploadAllowed returns an error if an attempt to upload tools should // not be allowed. func validateUploadAllowed(env environs.Environ, toolsArch, toolsSeries *string) error { // Now check that the architecture and series for which we are setting up an // environment matches that from which we are bootstrapping. hostArch := arch.HostArch() // We can't build tools for a different architecture if one is specified. if toolsArch != nil && *toolsArch != hostArch { return fmt.Errorf("cannot build tools for %q using a machine running on %q", *toolsArch, hostArch) } hostOS := jujuos.HostOS() if toolsSeries != nil { toolsSeriesOS, err := series.GetOSFromSeries(*toolsSeries) if err != nil { return errors.Trace(err) } if toolsSeriesOS != hostOS { return errors.Errorf("cannot build tools for %q using a machine running %q", *toolsSeries, hostOS) } } // If no architecture is specified, ensure the target provider supports instances matching our architecture. supportedArchitectures, err := env.SupportedArchitectures() if err != nil { return fmt.Errorf( "no packaged tools available and cannot determine model's supported architectures: %v", err) } archSupported := false for _, arch := range supportedArchitectures { if hostArch == arch { archSupported = true break } } if !archSupported { envType := env.Config().Type() return errors.Errorf("model %q of type %s does not support instances running on %q", env.Config().Name(), envType, hostArch) } return nil }
func socketName(baseDir, unitTag string) string { if os.HostOS() == os.Windows { return fmt.Sprintf(`\\.\pipe\collect-metrics-%s`, unitTag) } return path.Join(baseDir, defaultSocketName) }
reader, err := s.factory.Reader() if err != nil { return errors.Trace(err) } defer reader.Close() return s.sendMetrics(reader) } func (s *sender) stop() { if s.listener != nil { s.listener.Stop() } } var socketName = func(baseDir, unitTag string) string { if os.HostOS() == os.Windows { return fmt.Sprintf(`\\.\pipe\send-metrics-%s`, unitTag) } return path.Join(baseDir, defaultSocketName) } func newSender(client metricsadder.MetricsAdderClient, factory spool.MetricFactory, baseDir, unitTag string) (*sender, error) { s := &sender{ client: client, factory: factory, } listener, err := spool.NewSocketListener(socketName(baseDir, unitTag), s) if err != nil { return nil, errors.Trace(err) } s.listener = listener
func (u *Uniter) init(unitTag names.UnitTag) (err error) { u.unit, err = u.st.Unit(unitTag) if err != nil { return err } if u.unit.Life() == params.Dead { // If we started up already dead, we should not progress further. If we // become Dead immediately after starting up, we may well complete any // operations in progress before detecting it; but that race is fundamental // and inescapable, whereas this one is not. return worker.ErrTerminateAgent } if err = u.setupLocks(); err != nil { return err } if err := jujuc.EnsureSymlinks(u.paths.ToolsDir); err != nil { return err } if err := os.MkdirAll(u.paths.State.RelationsDir, 0755); err != nil { return errors.Trace(err) } relations, err := relation.NewRelations( u.st, unitTag, u.paths.State.CharmDir, u.paths.State.RelationsDir, u.catacomb.Dying(), ) if err != nil { return errors.Annotatef(err, "cannot create relations") } u.relations = relations storageAttachments, err := storage.NewAttachments( u.st, unitTag, u.paths.State.StorageDir, u.catacomb.Dying(), ) if err != nil { return errors.Annotatef(err, "cannot create storage hook source") } u.storage = storageAttachments u.commands = runcommands.NewCommands() u.commandChannel = make(chan string) deployer, err := charm.NewDeployer( u.paths.State.CharmDir, u.paths.State.DeployerDir, charm.NewBundlesDir(u.paths.State.BundlesDir, u.downloader), ) if err != nil { return errors.Annotatef(err, "cannot create deployer") } u.deployer = &deployerProxy{deployer} contextFactory, err := context.NewContextFactory( u.st, unitTag, u.leadershipTracker, u.relations.GetInfo, u.storage, u.paths, u.clock, ) if err != nil { return err } runnerFactory, err := runner.NewFactory( u.st, u.paths, contextFactory, ) if err != nil { return errors.Trace(err) } u.operationFactory = operation.NewFactory(operation.FactoryParams{ Deployer: u.deployer, RunnerFactory: runnerFactory, Callbacks: &operationCallbacks{u}, Abort: u.catacomb.Dying(), MetricSpoolDir: u.paths.GetMetricsSpoolDir(), }) operationExecutor, err := u.newOperationExecutor(u.paths.State.OperationsFile, u.getServiceCharmURL, u.acquireExecutionLock) if err != nil { return errors.Trace(err) } u.operationExecutor = operationExecutor logger.Debugf("starting juju-run listener on unix:%s", u.paths.Runtime.JujuRunSocket) commandRunner, err := NewChannelCommandRunner(ChannelCommandRunnerConfig{ Abort: u.catacomb.Dying(), Commands: u.commands, CommandChannel: u.commandChannel, }) if err != nil { return errors.Annotate(err, "creating command runner") } u.runListener, err = NewRunListener(RunListenerConfig{ SocketPath: u.paths.Runtime.JujuRunSocket, CommandRunner: commandRunner, }) if err != nil { return errors.Trace(err) } rlw := newRunListenerWrapper(u.runListener) if err := u.catacomb.Add(rlw); err != nil { return errors.Trace(err) } // The socket needs to have permissions 777 in order for other users to use it. if jujuos.HostOS() != jujuos.Windows { return os.Chmod(u.paths.Runtime.JujuRunSocket, 0777) } return nil }
// PrepareForBootstrap implements environs.EnvironProvider.PrepareForBootstrap. func (p environProvider) PrepareForBootstrap(ctx environs.BootstrapContext, cfg *config.Config) (environs.Environ, error) { attrs := map[string]interface{}{ // We must not proxy SSH through the API server in a // local provider environment. Besides not being useful, // it may not work; there is no requirement for sshd to // be available on machine-0. "proxy-ssh": false, } if _, ok := cfg.AgentVersion(); !ok { attrs["agent-version"] = version.Current.String() } if namespace, _ := cfg.UnknownAttrs()["namespace"].(string); namespace == "" { username := os.Getenv("USER") if username == "" { u, err := userCurrent() if err != nil { return nil, errors.Annotate(err, "failed to determine username for namespace") } username = u.Username } attrs["namespace"] = fmt.Sprintf("%s-%s", username, cfg.Name()) } setIfNotBlank := func(key, value string) { if value != "" { attrs[key] = value } } // If the user has specified no values for any of the four normal // proxies, then look in the environment and set them. logger.Tracef("Look for proxies?") if cfg.HttpProxy() == "" && cfg.HttpsProxy() == "" && cfg.FtpProxy() == "" && cfg.NoProxy() == "" { proxySettings := proxy.DetectProxies() logger.Tracef("Proxies detected %#v", proxySettings) setIfNotBlank(config.HttpProxyKey, proxySettings.Http) setIfNotBlank(config.HttpsProxyKey, proxySettings.Https) setIfNotBlank(config.FtpProxyKey, proxySettings.Ftp) setIfNotBlank(config.NoProxyKey, proxySettings.NoProxy) } if jujuos.HostOS() == jujuos.Ubuntu { if cfg.AptHttpProxy() == "" && cfg.AptHttpsProxy() == "" && cfg.AptFtpProxy() == "" { proxySettings, err := detectPackageProxies() if err != nil { return nil, errors.Trace(err) } setIfNotBlank(config.AptHttpProxyKey, proxySettings.Http) setIfNotBlank(config.AptHttpsProxyKey, proxySettings.Https) setIfNotBlank(config.AptFtpProxyKey, proxySettings.Ftp) } } cfg, err := cfg.Apply(attrs) if err != nil { return nil, errors.Trace(err) } // Make sure everything is valid. cfg, err = p.Validate(cfg, nil) if err != nil { return nil, errors.Trace(err) } // The user must not set bootstrap-ip; this is determined by the provider, // and its presence used to determine whether the environment has yet been // bootstrapped. if _, ok := cfg.UnknownAttrs()["bootstrap-ip"]; ok { return nil, errors.Errorf("bootstrap-ip must not be specified") } err = checkLocalPort(cfg.StatePort(), "state port") if err != nil { return nil, errors.Trace(err) } err = checkLocalPort(cfg.APIPort(), "API port") if err != nil { return nil, errors.Trace(err) } return p.Open(cfg) }
func (p *collectPaths) GetJujucSocket() string { if os.HostOS() == os.Windows { return fmt.Sprintf(`\\.\pipe\%s-metrics`, p.unitTag) } return filepath.Join(p.baseDir(), "metrics.socket@") }
func (s *prepareSuite) TestPrepareCapturesEnvironment(c *gc.C) { baseConfig, err := config.New(config.UseDefaults, map[string]interface{}{ "type": provider.Local, "name": "test", }) c.Assert(err, jc.ErrorIsNil) provider, err := environs.Provider(provider.Local) c.Assert(err, jc.ErrorIsNil) for i, test := range []struct { message string extraConfig map[string]interface{} env map[string]string aptOutput string expectedProxy proxy.Settings expectedAptProxy proxy.Settings }{{ message: "nothing set", }, { message: "grabs proxy from environment", env: map[string]string{ "http_proxy": "http://[email protected]", "HTTPS_PROXY": "https://[email protected]", "ftp_proxy": "ftp://[email protected]", "no_proxy": "localhost,10.0.3.1", }, expectedProxy: proxy.Settings{ Http: "http://[email protected]", Https: "https://[email protected]", Ftp: "ftp://[email protected]", NoProxy: "localhost,10.0.3.1", }, expectedAptProxy: proxy.Settings{ Http: "http://[email protected]", Https: "https://[email protected]", Ftp: "ftp://[email protected]", }, }, { message: "skips proxy from environment if http-proxy set", extraConfig: map[string]interface{}{ "http-proxy": "http://[email protected]", }, env: map[string]string{ "http_proxy": "http://[email protected]", "HTTPS_PROXY": "https://[email protected]", "ftp_proxy": "ftp://[email protected]", }, expectedProxy: proxy.Settings{ Http: "http://[email protected]", }, expectedAptProxy: proxy.Settings{ Http: "http://[email protected]", }, }, { message: "skips proxy from environment if https-proxy set", extraConfig: map[string]interface{}{ "https-proxy": "https://[email protected]", }, env: map[string]string{ "http_proxy": "http://[email protected]", "HTTPS_PROXY": "https://[email protected]", "ftp_proxy": "ftp://[email protected]", }, expectedProxy: proxy.Settings{ Https: "https://[email protected]", }, expectedAptProxy: proxy.Settings{ Https: "https://[email protected]", }, }, { message: "skips proxy from environment if ftp-proxy set", extraConfig: map[string]interface{}{ "ftp-proxy": "ftp://[email protected]", }, env: map[string]string{ "http_proxy": "http://[email protected]", "HTTPS_PROXY": "https://[email protected]", "ftp_proxy": "ftp://[email protected]", }, expectedProxy: proxy.Settings{ Ftp: "ftp://[email protected]", }, expectedAptProxy: proxy.Settings{ Ftp: "ftp://[email protected]", }, }, { message: "skips proxy from environment if no-proxy set", extraConfig: map[string]interface{}{ "no-proxy": "localhost,10.0.3.1", }, env: map[string]string{ "http_proxy": "http://[email protected]", "HTTPS_PROXY": "https://[email protected]", "ftp_proxy": "ftp://[email protected]", }, expectedProxy: proxy.Settings{ NoProxy: "localhost,10.0.3.1", }, }, { message: "apt-proxies detected", aptOutput: `CommandLine::AsString "apt-config dump"; Acquire::http::Proxy "10.0.3.1:3142"; Acquire::https::Proxy ""; Acquire::ftp::Proxy ""; Acquire::magic::Proxy ""; `, expectedAptProxy: proxy.Settings{ Http: "http://10.0.3.1:3142", Https: "", Ftp: "", }, }, { message: "apt-proxies not used if apt-http-proxy set", extraConfig: map[string]interface{}{ "apt-http-proxy": "http://value-set", }, aptOutput: `CommandLine::AsString "apt-config dump"; Acquire::http::Proxy "10.0.3.1:3142"; Acquire::https::Proxy ""; Acquire::ftp::Proxy ""; Acquire::magic::Proxy ""; `, expectedAptProxy: proxy.Settings{ Http: "http://value-set", }, }, { message: "apt-proxies not used if apt-https-proxy set", extraConfig: map[string]interface{}{ "apt-https-proxy": "https://value-set", }, aptOutput: `CommandLine::AsString "apt-config dump"; Acquire::http::Proxy "10.0.3.1:3142"; Acquire::https::Proxy ""; Acquire::ftp::Proxy ""; Acquire::magic::Proxy ""; `, expectedAptProxy: proxy.Settings{ Https: "https://value-set", }, }, { message: "apt-proxies not used if apt-ftp-proxy set", extraConfig: map[string]interface{}{ "apt-ftp-proxy": "ftp://value-set", }, aptOutput: `CommandLine::AsString "apt-config dump"; Acquire::http::Proxy "10.0.3.1:3142"; Acquire::https::Proxy ""; Acquire::ftp::Proxy ""; Acquire::magic::Proxy ""; `, expectedAptProxy: proxy.Settings{ Ftp: "ftp://value-set", }, }} { c.Logf("\n%v: %s", i, test.message) cleanup := []func(){} for key, value := range test.env { restore := testing.PatchEnvironment(key, value) cleanup = append(cleanup, restore) } _, restore := testing.HookCommandOutput(&manager.CommandOutput, []byte(test.aptOutput), nil) cleanup = append(cleanup, restore) testConfig := baseConfig if test.extraConfig != nil { testConfig, err = baseConfig.Apply(test.extraConfig) c.Assert(err, jc.ErrorIsNil) } env, err := provider.PrepareForBootstrap(envtesting.BootstrapContext(c), testConfig) c.Assert(err, jc.ErrorIsNil) envConfig := env.Config() c.Assert(envConfig.HttpProxy(), gc.Equals, test.expectedProxy.Http) c.Assert(envConfig.HttpsProxy(), gc.Equals, test.expectedProxy.Https) c.Assert(envConfig.FtpProxy(), gc.Equals, test.expectedProxy.Ftp) c.Assert(envConfig.NoProxy(), gc.Equals, test.expectedProxy.NoProxy) if jujuos.HostOS() == jujuos.Ubuntu { c.Assert(envConfig.AptHttpProxy(), gc.Equals, test.expectedAptProxy.Http) c.Assert(envConfig.AptHttpsProxy(), gc.Equals, test.expectedAptProxy.Https) c.Assert(envConfig.AptFtpProxy(), gc.Equals, test.expectedAptProxy.Ftp) } for _, clean := range cleanup { clean() } } }
func (cs *ConnectSuite) SetUpSuite(c *gc.C) { cs.IsolationSuite.SetUpSuite(c) if jujuos.HostOS() != jujuos.Ubuntu { c.Skip("lxd is only supported on Ubuntu at the moment") } }