github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/worker/provisioner/container_initialisation_test.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package provisioner_test 5 6 import ( 7 "fmt" 8 "io/ioutil" 9 "os" 10 "os/exec" 11 "path/filepath" 12 "runtime" 13 14 "github.com/juju/names" 15 "github.com/juju/testing" 16 jc "github.com/juju/testing/checkers" 17 "github.com/juju/utils/featureflag" 18 "github.com/juju/utils/fslock" 19 "github.com/juju/utils/packaging/manager" 20 gc "gopkg.in/check.v1" 21 22 "github.com/juju/juju/agent" 23 apiprovisioner "github.com/juju/juju/api/provisioner" 24 "github.com/juju/juju/container" 25 containertesting "github.com/juju/juju/container/testing" 26 "github.com/juju/juju/environs" 27 "github.com/juju/juju/feature" 28 "github.com/juju/juju/instance" 29 "github.com/juju/juju/juju/arch" 30 "github.com/juju/juju/juju/osenv" 31 "github.com/juju/juju/provider/dummy" 32 "github.com/juju/juju/state" 33 coretesting "github.com/juju/juju/testing" 34 "github.com/juju/juju/tools" 35 "github.com/juju/juju/version" 36 "github.com/juju/juju/worker" 37 "github.com/juju/juju/worker/provisioner" 38 ) 39 40 type ContainerSetupSuite struct { 41 CommonProvisionerSuite 42 p provisioner.Provisioner 43 agentConfig agent.ConfigSetter 44 // Record the apt commands issued as part of container initialisation 45 aptCmdChan <-chan *exec.Cmd 46 initLockDir string 47 initLock *fslock.Lock 48 fakeLXCNet string 49 } 50 51 var _ = gc.Suite(&ContainerSetupSuite{}) 52 53 func (s *ContainerSetupSuite) SetUpSuite(c *gc.C) { 54 // TODO(bogdanteleaga): Fix this on windows 55 if runtime.GOOS == "windows" { 56 c.Skip("bug 1403084: Skipping container tests on windows") 57 } 58 s.CommonProvisionerSuite.SetUpSuite(c) 59 } 60 61 func (s *ContainerSetupSuite) TearDownSuite(c *gc.C) { 62 s.CommonProvisionerSuite.TearDownSuite(c) 63 } 64 65 func allFatal(error) bool { 66 return true 67 } 68 69 func noImportance(err0, err1 error) bool { 70 return false 71 } 72 73 func (s *ContainerSetupSuite) SetUpTest(c *gc.C) { 74 s.CommonProvisionerSuite.SetUpTest(c) 75 aptCmdChan := s.HookCommandOutput(&manager.CommandOutput, []byte{}, nil) 76 s.aptCmdChan = aptCmdChan 77 78 // Set up provisioner for the state machine. 79 s.agentConfig = s.AgentConfigForTag(c, names.NewMachineTag("0")) 80 s.p = provisioner.NewEnvironProvisioner(s.provisioner, s.agentConfig) 81 82 // Create a new container initialisation lock. 83 s.initLockDir = c.MkDir() 84 initLock, err := fslock.NewLock(s.initLockDir, "container-init") 85 c.Assert(err, jc.ErrorIsNil) 86 s.initLock = initLock 87 88 // Patch to isolate the test from the host machine. 89 s.fakeLXCNet = filepath.Join(c.MkDir(), "lxc-net") 90 s.PatchValue(provisioner.EtcDefaultLXCNetPath, s.fakeLXCNet) 91 } 92 93 func (s *ContainerSetupSuite) TearDownTest(c *gc.C) { 94 stop(c, s.p) 95 s.CommonProvisionerSuite.TearDownTest(c) 96 } 97 98 func (s *ContainerSetupSuite) setupContainerWorker(c *gc.C, tag names.MachineTag) (worker.StringsWatchHandler, worker.Runner) { 99 testing.PatchExecutable(c, s, "ubuntu-cloudimg-query", containertesting.FakeLxcURLScript) 100 runner := worker.NewRunner(allFatal, noImportance) 101 pr := s.st.Provisioner() 102 machine, err := pr.Machine(tag) 103 c.Assert(err, jc.ErrorIsNil) 104 err = machine.SetSupportedContainers(instance.ContainerTypes...) 105 c.Assert(err, jc.ErrorIsNil) 106 cfg := s.AgentConfigForTag(c, tag) 107 108 watcherName := fmt.Sprintf("%s-container-watcher", machine.Id()) 109 params := provisioner.ContainerSetupParams{ 110 Runner: runner, 111 WorkerName: watcherName, 112 SupportedContainers: instance.ContainerTypes, 113 ImageURLGetter: &containertesting.MockURLGetter{}, 114 Machine: machine, 115 Provisioner: pr, 116 Config: cfg, 117 InitLock: s.initLock, 118 } 119 handler := provisioner.NewContainerSetupHandler(params) 120 runner.StartWorker(watcherName, func() (worker.Worker, error) { 121 return worker.NewStringsWorker(handler), nil 122 }) 123 return handler, runner 124 } 125 126 func (s *ContainerSetupSuite) createContainer(c *gc.C, host *state.Machine, ctype instance.ContainerType) { 127 inst := s.checkStartInstanceNoSecureConnection(c, host) 128 s.setupContainerWorker(c, host.Tag().(names.MachineTag)) 129 130 // make a container on the host machine 131 template := state.MachineTemplate{ 132 Series: coretesting.FakeDefaultSeries, 133 Jobs: []state.MachineJob{state.JobHostUnits}, 134 } 135 container, err := s.State.AddMachineInsideMachine(template, host.Id(), ctype) 136 c.Assert(err, jc.ErrorIsNil) 137 138 // the host machine agent should not attempt to create the container 139 s.checkNoOperations(c) 140 141 // cleanup 142 c.Assert(container.EnsureDead(), gc.IsNil) 143 c.Assert(container.Remove(), gc.IsNil) 144 c.Assert(host.EnsureDead(), gc.IsNil) 145 s.checkStopInstances(c, inst) 146 s.waitRemoved(c, host) 147 } 148 149 func (s *ContainerSetupSuite) assertContainerProvisionerStarted( 150 c *gc.C, host *state.Machine, ctype instance.ContainerType) { 151 152 // A stub worker callback to record what happens. 153 provisionerStarted := false 154 startProvisionerWorker := func(runner worker.Runner, containerType instance.ContainerType, 155 pr *apiprovisioner.State, cfg agent.Config, broker environs.InstanceBroker, 156 toolsFinder provisioner.ToolsFinder) error { 157 c.Assert(containerType, gc.Equals, ctype) 158 c.Assert(cfg.Tag(), gc.Equals, host.Tag()) 159 provisionerStarted = true 160 return nil 161 } 162 s.PatchValue(&provisioner.StartProvisioner, startProvisionerWorker) 163 164 s.createContainer(c, host, ctype) 165 // Consume the apt command used to initialise the container. 166 <-s.aptCmdChan 167 168 // the container worker should have created the provisioner 169 c.Assert(provisionerStarted, jc.IsTrue) 170 } 171 172 func (s *ContainerSetupSuite) TestContainerProvisionerStarted(c *gc.C) { 173 for _, ctype := range instance.ContainerTypes { 174 // create a machine to host the container. 175 m, err := s.BackingState.AddOneMachine(state.MachineTemplate{ 176 Series: coretesting.FakeDefaultSeries, 177 Jobs: []state.MachineJob{state.JobHostUnits}, 178 Constraints: s.defaultConstraints, 179 }) 180 c.Assert(err, jc.ErrorIsNil) 181 err = m.SetSupportedContainers([]instance.ContainerType{instance.LXC, instance.KVM}) 182 c.Assert(err, jc.ErrorIsNil) 183 err = m.SetAgentVersion(version.Current) 184 c.Assert(err, jc.ErrorIsNil) 185 s.assertContainerProvisionerStarted(c, m, ctype) 186 } 187 } 188 189 func (s *ContainerSetupSuite) TestLxcContainerUsesConstraintsArch(c *gc.C) { 190 // LXC should override the architecture in constraints with the 191 // host's architecture. 192 s.PatchValue(&version.Current.Arch, arch.PPC64EL) 193 s.testContainerConstraintsArch(c, instance.LXC, arch.PPC64EL) 194 } 195 196 func (s *ContainerSetupSuite) TestKvmContainerUsesHostArch(c *gc.C) { 197 // KVM should do what it's told, and use the architecture in 198 // constraints. 199 s.PatchValue(&version.Current.Arch, arch.PPC64EL) 200 s.testContainerConstraintsArch(c, instance.KVM, arch.AMD64) 201 } 202 203 func (s *ContainerSetupSuite) testContainerConstraintsArch(c *gc.C, containerType instance.ContainerType, expectArch string) { 204 var called bool 205 s.PatchValue(provisioner.GetToolsFinder, func(*apiprovisioner.State) provisioner.ToolsFinder { 206 return toolsFinderFunc(func(v version.Number, series string, arch *string) (tools.List, error) { 207 called = true 208 c.Assert(arch, gc.NotNil) 209 c.Assert(*arch, gc.Equals, expectArch) 210 result := version.Current 211 result.Number = v 212 result.Series = series 213 result.Arch = *arch 214 return tools.List{{Version: result}}, nil 215 }) 216 }) 217 218 s.PatchValue(&provisioner.StartProvisioner, func(runner worker.Runner, containerType instance.ContainerType, 219 pr *apiprovisioner.State, cfg agent.Config, broker environs.InstanceBroker, 220 toolsFinder provisioner.ToolsFinder) error { 221 amd64 := arch.AMD64 222 toolsFinder.FindTools(version.Current.Number, version.Current.Series, &amd64) 223 return nil 224 }) 225 226 // create a machine to host the container. 227 m, err := s.BackingState.AddOneMachine(state.MachineTemplate{ 228 Series: coretesting.FakeDefaultSeries, 229 Jobs: []state.MachineJob{state.JobHostUnits}, 230 Constraints: s.defaultConstraints, 231 }) 232 c.Assert(err, jc.ErrorIsNil) 233 err = m.SetSupportedContainers([]instance.ContainerType{containerType}) 234 c.Assert(err, jc.ErrorIsNil) 235 err = m.SetAgentVersion(version.Current) 236 c.Assert(err, jc.ErrorIsNil) 237 238 s.createContainer(c, m, containerType) 239 <-s.aptCmdChan 240 c.Assert(called, jc.IsTrue) 241 } 242 243 func (s *ContainerSetupSuite) TestLxcContainerUsesImageURL(c *gc.C) { 244 // create a machine to host the container. 245 m, err := s.BackingState.AddOneMachine(state.MachineTemplate{ 246 Series: coretesting.FakeDefaultSeries, 247 Jobs: []state.MachineJob{state.JobHostUnits}, 248 Constraints: s.defaultConstraints, 249 }) 250 c.Assert(err, jc.ErrorIsNil) 251 err = m.SetSupportedContainers([]instance.ContainerType{instance.LXC, instance.KVM}) 252 c.Assert(err, jc.ErrorIsNil) 253 err = m.SetAgentVersion(version.Current) 254 c.Assert(err, jc.ErrorIsNil) 255 256 brokerCalled := false 257 newlxcbroker := func(api provisioner.APICalls, agentConfig agent.Config, managerConfig container.ManagerConfig, 258 imageURLGetter container.ImageURLGetter, enableNAT bool, defaultMTU int) (environs.InstanceBroker, error) { 259 imageURL, err := imageURLGetter.ImageURL(instance.LXC, "trusty", "amd64") 260 c.Assert(err, jc.ErrorIsNil) 261 c.Assert(imageURL, gc.Equals, "imageURL") 262 c.Assert(imageURLGetter.CACert(), gc.DeepEquals, []byte("cert")) 263 brokerCalled = true 264 return nil, fmt.Errorf("lxc broker error") 265 } 266 s.PatchValue(&provisioner.NewLxcBroker, newlxcbroker) 267 s.createContainer(c, m, instance.LXC) 268 c.Assert(brokerCalled, jc.IsTrue) 269 } 270 271 func (s *ContainerSetupSuite) TestContainerManagerConfigName(c *gc.C) { 272 pr := s.st.Provisioner() 273 expect := func(expect string) { 274 cfg, err := provisioner.ContainerManagerConfig(instance.KVM, pr, s.agentConfig) 275 c.Assert(err, jc.ErrorIsNil) 276 c.Assert(cfg[container.ConfigName], gc.Equals, expect) 277 } 278 expect("juju") 279 s.agentConfig.SetValue(agent.Namespace, "any-old-thing") 280 expect("any-old-thing") 281 } 282 283 func (s *ContainerSetupSuite) assertContainerInitialised(c *gc.C, ctype instance.ContainerType, packages [][]string, addressable bool) { 284 // A noop worker callback. 285 startProvisionerWorker := func(runner worker.Runner, containerType instance.ContainerType, 286 pr *apiprovisioner.State, cfg agent.Config, broker environs.InstanceBroker, 287 toolsFinder provisioner.ToolsFinder) error { 288 return nil 289 } 290 s.PatchValue(&provisioner.StartProvisioner, startProvisionerWorker) 291 292 // create a machine to host the container. 293 m, err := s.BackingState.AddOneMachine(state.MachineTemplate{ 294 Series: "precise", // precise requires special apt parameters, so we use that series here. 295 Jobs: []state.MachineJob{state.JobHostUnits}, 296 Constraints: s.defaultConstraints, 297 }) 298 c.Assert(err, jc.ErrorIsNil) 299 err = m.SetSupportedContainers([]instance.ContainerType{instance.LXC, instance.KVM}) 300 c.Assert(err, jc.ErrorIsNil) 301 err = m.SetAgentVersion(version.Current) 302 c.Assert(err, jc.ErrorIsNil) 303 304 // Before starting /etc/default/lxc-net should be missing. 305 c.Assert(s.fakeLXCNet, jc.DoesNotExist) 306 307 s.createContainer(c, m, ctype) 308 309 // Only feature-flagged addressable containers modify lxc-net. 310 if addressable { 311 // After initialisation starts, but before running the 312 // initializer, lxc-net should be created if ctype is LXC, as the 313 // dummy provider supports static address allocation by default. 314 if ctype == instance.LXC { 315 AssertFileContains(c, s.fakeLXCNet, provisioner.EtcDefaultLXCNet) 316 defer os.Remove(s.fakeLXCNet) 317 } else { 318 c.Assert(s.fakeLXCNet, jc.DoesNotExist) 319 } 320 } 321 322 for _, pack := range packages { 323 cmd := <-s.aptCmdChan 324 expected := []string{ 325 "apt-get", "--option=Dpkg::Options::=--force-confold", 326 "--option=Dpkg::options::=--force-unsafe-io", "--assume-yes", "--quiet", 327 "install"} 328 expected = append(expected, pack...) 329 c.Assert(cmd.Args, gc.DeepEquals, expected) 330 } 331 } 332 333 func (s *ContainerSetupSuite) TestContainerInitialised(c *gc.C) { 334 for _, test := range []struct { 335 ctype instance.ContainerType 336 packages [][]string 337 }{ 338 {instance.LXC, [][]string{ 339 []string{"--target-release", "precise-updates/cloud-tools", "lxc"}, 340 []string{"--target-release", "precise-updates/cloud-tools", "cloud-image-utils"}}}, 341 {instance.KVM, [][]string{ 342 []string{"uvtool-libvirt"}, 343 []string{"uvtool"}}}, 344 } { 345 s.assertContainerInitialised(c, test.ctype, test.packages, false) 346 } 347 } 348 349 func (s *ContainerSetupSuite) TestContainerInitLockError(c *gc.C) { 350 m, err := s.BackingState.AddOneMachine(state.MachineTemplate{ 351 Series: coretesting.FakeDefaultSeries, 352 Jobs: []state.MachineJob{state.JobHostUnits}, 353 Constraints: s.defaultConstraints, 354 }) 355 c.Assert(err, jc.ErrorIsNil) 356 err = m.SetAgentVersion(version.Current) 357 c.Assert(err, jc.ErrorIsNil) 358 359 err = os.RemoveAll(s.initLockDir) 360 c.Assert(err, jc.ErrorIsNil) 361 handler, runner := s.setupContainerWorker(c, m.Tag().(names.MachineTag)) 362 runner.Kill() 363 err = runner.Wait() 364 c.Assert(err, jc.ErrorIsNil) 365 366 _, err = handler.SetUp() 367 c.Assert(err, jc.ErrorIsNil) 368 err = handler.Handle([]string{"0/lxc/0"}) 369 c.Assert(err, gc.ErrorMatches, ".*failed to acquire initialization lock:.*") 370 371 } 372 373 func (s *ContainerSetupSuite) TestMaybeOverrideDefaultLXCNet(c *gc.C) { 374 for i, test := range []struct { 375 ctype instance.ContainerType 376 addressable bool 377 expectOverride bool 378 }{ 379 {instance.KVM, false, false}, 380 {instance.KVM, true, false}, 381 {instance.LXC, false, false}, 382 {instance.LXC, true, true}, // the only case when we override; also last 383 } { 384 c.Logf( 385 "test %d: ctype: %q, addressable: %v -> expectOverride: %v", 386 i, test.ctype, test.addressable, test.expectOverride, 387 ) 388 err := provisioner.MaybeOverrideDefaultLXCNet(test.ctype, test.addressable) 389 if !c.Check(err, jc.ErrorIsNil) { 390 continue 391 } 392 if !test.expectOverride { 393 c.Check(s.fakeLXCNet, jc.DoesNotExist) 394 } else { 395 AssertFileContains(c, s.fakeLXCNet, provisioner.EtcDefaultLXCNet) 396 } 397 } 398 } 399 400 func AssertFileContains(c *gc.C, filename string, expectedContent ...string) { 401 // TODO(dimitern): We should put this in juju/testing repo and 402 // replace all similar checks with it. 403 data, err := ioutil.ReadFile(filename) 404 c.Assert(err, jc.ErrorIsNil) 405 for _, s := range expectedContent { 406 c.Assert(string(data), jc.Contains, s) 407 } 408 } 409 410 func AssertFileContents(c *gc.C, checker gc.Checker, filename string, expectedContent ...string) { 411 // TODO(dimitern): We should put this in juju/testing repo and 412 // replace all similar checks with it. 413 data, err := ioutil.ReadFile(filename) 414 c.Assert(err, jc.ErrorIsNil) 415 for _, s := range expectedContent { 416 c.Assert(string(data), checker, s) 417 } 418 } 419 420 type SetIPAndARPForwardingSuite struct { 421 coretesting.BaseSuite 422 } 423 424 func (s *SetIPAndARPForwardingSuite) SetUpSuite(c *gc.C) { 425 if runtime.GOOS == "windows" { 426 c.Skip("bug 1403084: Skipping for now") 427 } 428 s.BaseSuite.SetUpSuite(c) 429 } 430 431 var _ = gc.Suite(&SetIPAndARPForwardingSuite{}) 432 433 func (s *SetIPAndARPForwardingSuite) TestSuccess(c *gc.C) { 434 // NOTE: Because PatchExecutableAsEchoArgs does not allow us to 435 // assert on earlier invocations of the same binary (each run 436 // overwrites the last args used), we only check sysctl was called 437 // for the second key (arpProxySysctlKey). We do check the config 438 // contains both though. 439 fakeConfig := filepath.Join(c.MkDir(), "sysctl.conf") 440 testing.PatchExecutableAsEchoArgs(c, s, "sysctl") 441 s.PatchValue(provisioner.SysctlConfig, fakeConfig) 442 443 err := provisioner.SetIPAndARPForwarding(true) 444 c.Assert(err, jc.ErrorIsNil) 445 expectConf := fmt.Sprintf( 446 "%s=1\n%s=1", 447 provisioner.IPForwardSysctlKey, 448 provisioner.ARPProxySysctlKey, 449 ) 450 AssertFileContains(c, fakeConfig, expectConf) 451 expectKeyVal := fmt.Sprintf("%s=1", provisioner.IPForwardSysctlKey) 452 testing.AssertEchoArgs(c, "sysctl", "-w", expectKeyVal) 453 expectKeyVal = fmt.Sprintf("%s=1", provisioner.ARPProxySysctlKey) 454 testing.AssertEchoArgs(c, "sysctl", "-w", expectKeyVal) 455 456 err = provisioner.SetIPAndARPForwarding(false) 457 c.Assert(err, jc.ErrorIsNil) 458 expectConf = fmt.Sprintf( 459 "%s=0\n%s=0", 460 provisioner.IPForwardSysctlKey, 461 provisioner.ARPProxySysctlKey, 462 ) 463 AssertFileContains(c, fakeConfig, expectConf) 464 expectKeyVal = fmt.Sprintf("%s=0", provisioner.IPForwardSysctlKey) 465 testing.AssertEchoArgs(c, "sysctl", "-w", expectKeyVal) 466 expectKeyVal = fmt.Sprintf("%s=0", provisioner.ARPProxySysctlKey) 467 testing.AssertEchoArgs(c, "sysctl", "-w", expectKeyVal) 468 } 469 470 func (s *SetIPAndARPForwardingSuite) TestFailure(c *gc.C) { 471 fakeConfig := filepath.Join(c.MkDir(), "sysctl.conf") 472 testing.PatchExecutableThrowError(c, s, "sysctl", 123) 473 s.PatchValue(provisioner.SysctlConfig, fakeConfig) 474 expectKeyVal := fmt.Sprintf("%s=1", provisioner.IPForwardSysctlKey) 475 476 err := provisioner.SetIPAndARPForwarding(true) 477 c.Assert(err, gc.ErrorMatches, fmt.Sprintf( 478 `cannot set %s: unexpected exit code 123`, expectKeyVal), 479 ) 480 _, err = os.Stat(fakeConfig) 481 c.Assert(err, jc.Satisfies, os.IsNotExist) 482 } 483 484 type toolsFinderFunc func(v version.Number, series string, arch *string) (tools.List, error) 485 486 func (t toolsFinderFunc) FindTools(v version.Number, series string, arch *string) (tools.List, error) { 487 return t(v, series, arch) 488 } 489 490 // AddressableContainerSetupSuite only contains tests depending on the 491 // address allocation feature flag being enabled. 492 type AddressableContainerSetupSuite struct { 493 ContainerSetupSuite 494 } 495 496 var _ = gc.Suite(&AddressableContainerSetupSuite{}) 497 498 func (s *AddressableContainerSetupSuite) enableFeatureFlag() { 499 s.SetFeatureFlags(feature.AddressAllocation) 500 featureflag.SetFlagsFromEnvironment(osenv.JujuFeatureFlagEnvKey) 501 } 502 503 func (s *AddressableContainerSetupSuite) TestContainerInitialised(c *gc.C) { 504 for _, test := range []struct { 505 ctype instance.ContainerType 506 packages [][]string 507 }{ 508 {instance.LXC, [][]string{{"--target-release", "precise-updates/cloud-tools", "lxc"}, {"--target-release", "precise-updates/cloud-tools", "cloud-image-utils"}}}, 509 {instance.KVM, [][]string{{"uvtool-libvirt"}, {"uvtool"}}}, 510 } { 511 s.enableFeatureFlag() 512 s.assertContainerInitialised(c, test.ctype, test.packages, true) 513 } 514 } 515 516 // LXCDefaultMTUSuite only contains tests depending on the 517 // lxc-default-mtu environment setting being set explicitly. 518 type LXCDefaultMTUSuite struct { 519 ContainerSetupSuite 520 } 521 522 var _ = gc.Suite(&LXCDefaultMTUSuite{}) 523 524 func (s *LXCDefaultMTUSuite) SetUpTest(c *gc.C) { 525 // Explicitly set lxc-default-mtu before JujuConnSuite constructs 526 // the environment, as the setting is immutable. 527 s.DummyConfig = dummy.SampleConfig() 528 s.DummyConfig["lxc-default-mtu"] = 9000 529 s.ContainerSetupSuite.SetUpTest(c) 530 } 531 532 func (s *LXCDefaultMTUSuite) TestDefaultMTUPropagatedToNewLXCBroker(c *gc.C) { 533 // create a machine to host the container. 534 m, err := s.BackingState.AddOneMachine(state.MachineTemplate{ 535 Series: coretesting.FakeDefaultSeries, 536 Jobs: []state.MachineJob{state.JobHostUnits}, 537 Constraints: s.defaultConstraints, 538 }) 539 c.Assert(err, jc.ErrorIsNil) 540 err = m.SetSupportedContainers([]instance.ContainerType{instance.LXC, instance.KVM}) 541 c.Assert(err, jc.ErrorIsNil) 542 err = m.SetAgentVersion(version.Current) 543 c.Assert(err, jc.ErrorIsNil) 544 545 brokerCalled := false 546 newlxcbroker := func(api provisioner.APICalls, agentConfig agent.Config, managerConfig container.ManagerConfig, imageURLGetter container.ImageURLGetter, enableNAT bool, defaultMTU int) (environs.InstanceBroker, error) { 547 brokerCalled = true 548 c.Assert(defaultMTU, gc.Equals, 9000) 549 return nil, fmt.Errorf("lxc broker error") 550 } 551 s.PatchValue(&provisioner.NewLxcBroker, newlxcbroker) 552 s.createContainer(c, m, instance.LXC) 553 c.Assert(brokerCalled, jc.IsTrue) 554 }