github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/provider/local/environprovider_test.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package local_test 5 6 import ( 7 "errors" 8 "fmt" 9 "os/user" 10 11 "github.com/juju/loggo" 12 "github.com/juju/testing" 13 jc "github.com/juju/testing/checkers" 14 "github.com/juju/utils/packaging/manager" 15 "github.com/juju/utils/proxy" 16 gc "gopkg.in/check.v1" 17 18 lxctesting "github.com/juju/juju/container/lxc/testing" 19 "github.com/juju/juju/environs" 20 "github.com/juju/juju/environs/config" 21 envtesting "github.com/juju/juju/environs/testing" 22 "github.com/juju/juju/instance" 23 "github.com/juju/juju/provider" 24 "github.com/juju/juju/provider/local" 25 coretesting "github.com/juju/juju/testing" 26 jujuos "github.com/juju/utils/os" 27 ) 28 29 type baseProviderSuite struct { 30 lxctesting.TestSuite 31 restore func() 32 } 33 34 func (s *baseProviderSuite) SetUpTest(c *gc.C) { 35 s.TestSuite.SetUpTest(c) 36 loggo.GetLogger("juju.provider.local").SetLogLevel(loggo.TRACE) 37 s.restore = local.MockAddressForInterface() 38 s.PatchValue(&local.VerifyPrerequisites, func(containerType instance.ContainerType) error { 39 return nil 40 }) 41 } 42 43 func (s *baseProviderSuite) TearDownTest(c *gc.C) { 44 s.restore() 45 s.TestSuite.TearDownTest(c) 46 } 47 48 type prepareSuite struct { 49 coretesting.FakeJujuHomeSuite 50 } 51 52 var _ = gc.Suite(&prepareSuite{}) 53 54 func (s *prepareSuite) SetUpTest(c *gc.C) { 55 s.FakeJujuHomeSuite.SetUpTest(c) 56 loggo.GetLogger("juju.provider.local").SetLogLevel(loggo.TRACE) 57 s.PatchEnvironment("http_proxy", "") 58 s.PatchEnvironment("HTTP_PROXY", "") 59 s.PatchEnvironment("https_proxy", "") 60 s.PatchEnvironment("HTTPS_PROXY", "") 61 s.PatchEnvironment("ftp_proxy", "") 62 s.PatchEnvironment("FTP_PROXY", "") 63 s.PatchEnvironment("no_proxy", "") 64 s.PatchEnvironment("NO_PROXY", "") 65 s.HookCommandOutput(&manager.CommandOutput, nil, nil) 66 s.PatchValue(local.CheckLocalPort, func(port int, desc string) error { 67 return nil 68 }) 69 restore := local.MockAddressForInterface() 70 s.AddCleanup(func(*gc.C) { restore() }) 71 } 72 73 func (s *prepareSuite) TestPrepareCapturesEnvironment(c *gc.C) { 74 baseConfig, err := config.New(config.UseDefaults, map[string]interface{}{ 75 "type": provider.Local, 76 "name": "test", 77 }) 78 c.Assert(err, jc.ErrorIsNil) 79 provider, err := environs.Provider(provider.Local) 80 c.Assert(err, jc.ErrorIsNil) 81 82 for i, test := range []struct { 83 message string 84 extraConfig map[string]interface{} 85 env map[string]string 86 aptOutput string 87 expectedProxy proxy.Settings 88 expectedAptProxy proxy.Settings 89 }{{ 90 message: "nothing set", 91 }, { 92 message: "grabs proxy from environment", 93 env: map[string]string{ 94 "http_proxy": "http://user@10.0.0.1", 95 "HTTPS_PROXY": "https://user@10.0.0.1", 96 "ftp_proxy": "ftp://user@10.0.0.1", 97 "no_proxy": "localhost,10.0.3.1", 98 }, 99 expectedProxy: proxy.Settings{ 100 Http: "http://user@10.0.0.1", 101 Https: "https://user@10.0.0.1", 102 Ftp: "ftp://user@10.0.0.1", 103 NoProxy: "localhost,10.0.3.1", 104 }, 105 expectedAptProxy: proxy.Settings{ 106 Http: "http://user@10.0.0.1", 107 Https: "https://user@10.0.0.1", 108 Ftp: "ftp://user@10.0.0.1", 109 }, 110 }, { 111 message: "skips proxy from environment if http-proxy set", 112 extraConfig: map[string]interface{}{ 113 "http-proxy": "http://user@10.0.0.42", 114 }, 115 env: map[string]string{ 116 "http_proxy": "http://user@10.0.0.1", 117 "HTTPS_PROXY": "https://user@10.0.0.1", 118 "ftp_proxy": "ftp://user@10.0.0.1", 119 }, 120 expectedProxy: proxy.Settings{ 121 Http: "http://user@10.0.0.42", 122 }, 123 expectedAptProxy: proxy.Settings{ 124 Http: "http://user@10.0.0.42", 125 }, 126 }, { 127 message: "skips proxy from environment if https-proxy set", 128 extraConfig: map[string]interface{}{ 129 "https-proxy": "https://user@10.0.0.42", 130 }, 131 env: map[string]string{ 132 "http_proxy": "http://user@10.0.0.1", 133 "HTTPS_PROXY": "https://user@10.0.0.1", 134 "ftp_proxy": "ftp://user@10.0.0.1", 135 }, 136 expectedProxy: proxy.Settings{ 137 Https: "https://user@10.0.0.42", 138 }, 139 expectedAptProxy: proxy.Settings{ 140 Https: "https://user@10.0.0.42", 141 }, 142 }, { 143 message: "skips proxy from environment if ftp-proxy set", 144 extraConfig: map[string]interface{}{ 145 "ftp-proxy": "ftp://user@10.0.0.42", 146 }, 147 env: map[string]string{ 148 "http_proxy": "http://user@10.0.0.1", 149 "HTTPS_PROXY": "https://user@10.0.0.1", 150 "ftp_proxy": "ftp://user@10.0.0.1", 151 }, 152 expectedProxy: proxy.Settings{ 153 Ftp: "ftp://user@10.0.0.42", 154 }, 155 expectedAptProxy: proxy.Settings{ 156 Ftp: "ftp://user@10.0.0.42", 157 }, 158 }, { 159 message: "skips proxy from environment if no-proxy set", 160 extraConfig: map[string]interface{}{ 161 "no-proxy": "localhost,10.0.3.1", 162 }, 163 env: map[string]string{ 164 "http_proxy": "http://user@10.0.0.1", 165 "HTTPS_PROXY": "https://user@10.0.0.1", 166 "ftp_proxy": "ftp://user@10.0.0.1", 167 }, 168 expectedProxy: proxy.Settings{ 169 NoProxy: "localhost,10.0.3.1", 170 }, 171 }, { 172 message: "apt-proxies detected", 173 aptOutput: `CommandLine::AsString "apt-config dump"; 174 Acquire::http::Proxy "10.0.3.1:3142"; 175 Acquire::https::Proxy ""; 176 Acquire::ftp::Proxy ""; 177 Acquire::magic::Proxy ""; 178 `, 179 expectedAptProxy: proxy.Settings{ 180 Http: "http://10.0.3.1:3142", 181 Https: "", 182 Ftp: "", 183 }, 184 }, { 185 message: "apt-proxies not used if apt-http-proxy set", 186 extraConfig: map[string]interface{}{ 187 "apt-http-proxy": "http://value-set", 188 }, 189 aptOutput: `CommandLine::AsString "apt-config dump"; 190 Acquire::http::Proxy "10.0.3.1:3142"; 191 Acquire::https::Proxy ""; 192 Acquire::ftp::Proxy ""; 193 Acquire::magic::Proxy ""; 194 `, 195 expectedAptProxy: proxy.Settings{ 196 Http: "http://value-set", 197 }, 198 }, { 199 message: "apt-proxies not used if apt-https-proxy set", 200 extraConfig: map[string]interface{}{ 201 "apt-https-proxy": "https://value-set", 202 }, 203 aptOutput: `CommandLine::AsString "apt-config dump"; 204 Acquire::http::Proxy "10.0.3.1:3142"; 205 Acquire::https::Proxy ""; 206 Acquire::ftp::Proxy ""; 207 Acquire::magic::Proxy ""; 208 `, 209 expectedAptProxy: proxy.Settings{ 210 Https: "https://value-set", 211 }, 212 }, { 213 message: "apt-proxies not used if apt-ftp-proxy set", 214 extraConfig: map[string]interface{}{ 215 "apt-ftp-proxy": "ftp://value-set", 216 }, 217 aptOutput: `CommandLine::AsString "apt-config dump"; 218 Acquire::http::Proxy "10.0.3.1:3142"; 219 Acquire::https::Proxy ""; 220 Acquire::ftp::Proxy ""; 221 Acquire::magic::Proxy ""; 222 `, 223 expectedAptProxy: proxy.Settings{ 224 Ftp: "ftp://value-set", 225 }, 226 }} { 227 c.Logf("\n%v: %s", i, test.message) 228 cleanup := []func(){} 229 for key, value := range test.env { 230 restore := testing.PatchEnvironment(key, value) 231 cleanup = append(cleanup, restore) 232 } 233 _, restore := testing.HookCommandOutput(&manager.CommandOutput, []byte(test.aptOutput), nil) 234 cleanup = append(cleanup, restore) 235 testConfig := baseConfig 236 if test.extraConfig != nil { 237 testConfig, err = baseConfig.Apply(test.extraConfig) 238 c.Assert(err, jc.ErrorIsNil) 239 } 240 env, err := provider.PrepareForBootstrap(envtesting.BootstrapContext(c), testConfig) 241 c.Assert(err, jc.ErrorIsNil) 242 243 envConfig := env.Config() 244 c.Assert(envConfig.HttpProxy(), gc.Equals, test.expectedProxy.Http) 245 c.Assert(envConfig.HttpsProxy(), gc.Equals, test.expectedProxy.Https) 246 c.Assert(envConfig.FtpProxy(), gc.Equals, test.expectedProxy.Ftp) 247 c.Assert(envConfig.NoProxy(), gc.Equals, test.expectedProxy.NoProxy) 248 249 if jujuos.HostOS() == jujuos.Ubuntu { 250 c.Assert(envConfig.AptHttpProxy(), gc.Equals, test.expectedAptProxy.Http) 251 c.Assert(envConfig.AptHttpsProxy(), gc.Equals, test.expectedAptProxy.Https) 252 c.Assert(envConfig.AptFtpProxy(), gc.Equals, test.expectedAptProxy.Ftp) 253 } 254 for _, clean := range cleanup { 255 clean() 256 } 257 } 258 } 259 260 func (s *prepareSuite) TestPrepareNamespace(c *gc.C) { 261 s.PatchValue(local.DetectPackageProxies, func() (proxy.Settings, error) { 262 return proxy.Settings{}, nil 263 }) 264 basecfg, err := config.New(config.UseDefaults, map[string]interface{}{ 265 "type": "local", 266 "name": "test", 267 }) 268 provider, err := environs.Provider("local") 269 c.Assert(err, jc.ErrorIsNil) 270 271 type test struct { 272 userEnv string 273 userOS string 274 userOSErr error 275 namespace string 276 err string 277 } 278 tests := []test{{ 279 userEnv: "someone", 280 userOS: "other", 281 namespace: "someone-test", 282 }, { 283 userOS: "other", 284 namespace: "other-test", 285 }, { 286 userOSErr: errors.New("oh noes"), 287 err: "failed to determine username for namespace: oh noes", 288 }} 289 290 for i, test := range tests { 291 c.Logf("test %d: %v", i, test) 292 s.PatchEnvironment("USER", test.userEnv) 293 s.PatchValue(local.UserCurrent, func() (*user.User, error) { 294 return &user.User{Username: test.userOS}, test.userOSErr 295 }) 296 env, err := provider.PrepareForBootstrap(envtesting.BootstrapContext(c), basecfg) 297 if test.err == "" { 298 c.Assert(err, jc.ErrorIsNil) 299 cfg := env.Config() 300 c.Assert(cfg.UnknownAttrs()["namespace"], gc.Equals, test.namespace) 301 } else { 302 c.Assert(err, gc.ErrorMatches, test.err) 303 } 304 } 305 } 306 307 func (s *prepareSuite) TestPrepareProxySSH(c *gc.C) { 308 s.PatchValue(local.DetectPackageProxies, func() (proxy.Settings, error) { 309 return proxy.Settings{}, nil 310 }) 311 basecfg, err := config.New(config.UseDefaults, map[string]interface{}{ 312 "type": "local", 313 "name": "test", 314 }) 315 provider, err := environs.Provider("local") 316 c.Assert(err, jc.ErrorIsNil) 317 env, err := provider.PrepareForBootstrap(envtesting.BootstrapContext(c), basecfg) 318 c.Assert(err, jc.ErrorIsNil) 319 // local provider sets proxy-ssh to false 320 c.Assert(env.Config().ProxySSH(), jc.IsFalse) 321 } 322 323 func (s *prepareSuite) TestProxyLocalhostFix(c *gc.C) { 324 basecfg, err := config.New(config.UseDefaults, map[string]interface{}{ 325 "type": "local", 326 "name": "test", 327 }) 328 c.Assert(err, jc.ErrorIsNil) 329 provider, err := environs.Provider(provider.Local) 330 c.Assert(err, jc.ErrorIsNil) 331 332 //URL protocol is irrelelvant as we are only interested in it as string 333 urlConstruct := "http://%v%v" 334 // This value is currently hard-coded in export_test and is called on by this test setup. @see export_test.go MockAddressForInterface() 335 expectedBridge := "127.0.0.1" 336 for i, test := range urlReplacementTests { 337 c.Logf("test %d: %v\n", i, test.message) 338 339 //construct proxy env attributes based on the test scenario 340 proxyAttrValues := map[string]interface{}{} 341 for _, anAttrKey := range config.ProxyAttributes { 342 proxyAttrValues[anAttrKey] = fmt.Sprintf(urlConstruct, test.url, test.port) 343 } 344 345 //Update env config to include new attributes 346 cfg, err := basecfg.Apply(proxyAttrValues) 347 c.Assert(err, jc.ErrorIsNil) 348 //this call should replace all loopback urls with bridge ip 349 env, err := provider.PrepareForBootstrap(envtesting.BootstrapContext(c), cfg) 350 c.Assert(err, jc.ErrorIsNil) 351 352 // verify that correct replacement took place 353 envConfig := env.Config().AllAttrs() 354 for _, anAttrKey := range config.ProxyAttributes { 355 //expected value is either unchanged original 356 expectedAttValue := proxyAttrValues[anAttrKey] 357 if test.expectChange { 358 // or expected value has bridge ip substituted for localhost variations 359 expectedAttValue = fmt.Sprintf(urlConstruct, expectedBridge, test.port) 360 } 361 c.Assert(envConfig[anAttrKey].(string), gc.Equals, expectedAttValue.(string)) 362 } 363 } 364 } 365 366 type testURL struct { 367 message string 368 url string 369 port string 370 expectChange bool 371 } 372 373 var urlReplacementTests = []testURL{{ 374 message: "replace localhost with bridge ip in proxy url", 375 url: "localhost", 376 port: "", 377 expectChange: true, 378 }, { 379 message: "replace localhost:port with bridge ip:port in proxy url", 380 url: "localhost", 381 port: ":8877", 382 expectChange: true, 383 }, { 384 message: "replace 127.2.0.1 with bridge ip in proxy url", 385 url: "127.2.0.1", 386 port: "", 387 expectChange: true, 388 }, { 389 message: "replace 127.2.0.1:port with bridge ip:port in proxy url", 390 url: "127.2.0.1", 391 port: ":8877", 392 expectChange: true, 393 }, { 394 message: "replace [::1]:port with bridge ip:port in proxy url", 395 url: "[::1]", 396 port: ":8877", 397 expectChange: true, 398 }, { 399 // Note that http//::1 (without the square brackets) 400 // is not a legal URL. See https://www.ietf.org/rfc/rfc2732.txt. 401 message: "replace [::1] with bridge ip in proxy url", 402 url: "[::1]", 403 port: "", 404 expectChange: true, 405 }, { 406 message: "do not replace provided with bridge ip in proxy url", 407 url: "www.google.com", 408 port: "", 409 expectChange: false, 410 }, { 411 message: "do not replace provided:port with bridge ip:port in proxy url", 412 url: "www.google.com", 413 port: ":8877", 414 expectChange: false, 415 }, { 416 message: "lp 1437296 - apt-http-proxy being reset to bridge address when shouldn't", 417 url: "192.168.1.201", 418 port: ":8000", 419 expectChange: false, 420 }, 421 }