github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/environs/jujutest/livetests.go (about) 1 // Copyright 2011, 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package jujutest 5 6 import ( 7 stdcontext "context" 8 "fmt" 9 "path/filepath" 10 "strconv" 11 "time" 12 13 "github.com/juju/charm/v12" 14 "github.com/juju/errors" 15 gitjujutesting "github.com/juju/testing" 16 jc "github.com/juju/testing/checkers" 17 "github.com/juju/utils/v3" 18 "github.com/juju/version/v2" 19 gc "gopkg.in/check.v1" 20 21 "github.com/juju/juju/api" 22 apiclient "github.com/juju/juju/api/client/client" 23 "github.com/juju/juju/cloud" 24 "github.com/juju/juju/cloudconfig/instancecfg" 25 "github.com/juju/juju/core/arch" 26 corebase "github.com/juju/juju/core/base" 27 "github.com/juju/juju/core/constraints" 28 "github.com/juju/juju/core/instance" 29 "github.com/juju/juju/core/network" 30 "github.com/juju/juju/core/network/firewall" 31 "github.com/juju/juju/core/status" 32 "github.com/juju/juju/environs" 33 "github.com/juju/juju/environs/bootstrap" 34 environscloudspec "github.com/juju/juju/environs/cloudspec" 35 "github.com/juju/juju/environs/config" 36 "github.com/juju/juju/environs/context" 37 "github.com/juju/juju/environs/filestorage" 38 "github.com/juju/juju/environs/instances" 39 "github.com/juju/juju/environs/models" 40 "github.com/juju/juju/environs/simplestreams" 41 sstesting "github.com/juju/juju/environs/simplestreams/testing" 42 "github.com/juju/juju/environs/storage" 43 "github.com/juju/juju/environs/sync" 44 envtesting "github.com/juju/juju/environs/testing" 45 envtools "github.com/juju/juju/environs/tools" 46 envtoolstesting "github.com/juju/juju/environs/tools/testing" 47 "github.com/juju/juju/juju/keys" 48 jujutesting "github.com/juju/juju/juju/testing" 49 "github.com/juju/juju/jujuclient" 50 "github.com/juju/juju/provider/dummy" 51 "github.com/juju/juju/state" 52 stateerrors "github.com/juju/juju/state/errors" 53 statetesting "github.com/juju/juju/state/testing" 54 "github.com/juju/juju/testcharms" 55 coretesting "github.com/juju/juju/testing" 56 coretools "github.com/juju/juju/tools" 57 jujuversion "github.com/juju/juju/version" 58 ) 59 60 const ( 61 AdminSecret = "admin-secret" 62 ) 63 64 // LiveTests contains tests that are designed to run against a live server 65 // (e.g. Amazon EC2). The Environ is opened once only for all the tests 66 // in the suite, stored in Env, and Destroyed after the suite has completed. 67 type LiveTests struct { 68 gitjujutesting.CleanupSuite 69 70 envtesting.ToolsFixture 71 sstesting.TestDataSuite 72 73 // TestConfig contains the configuration attributes for opening an environment. 74 TestConfig coretesting.Attrs 75 76 // Credential contains the credential for preparing an environment for 77 // bootstrapping. If this is unset, empty credentials will be used. 78 Credential cloud.Credential 79 80 // CloudRegion contains the cloud region name to create resources in. 81 CloudRegion string 82 83 // CloudEndpoint contains the cloud API endpoint to communicate with. 84 CloudEndpoint string 85 86 // Attempt holds a strategy for waiting until the environment 87 // becomes logically consistent. 88 // 89 // TODO(katco): 2016-08-09: lp:1611427 90 Attempt utils.AttemptStrategy 91 92 // CanOpenState should be true if the testing environment allows 93 // the state to be opened after bootstrapping. 94 CanOpenState bool 95 96 // HasProvisioner should be true if the environment has 97 // a provisioning agent. 98 HasProvisioner bool 99 100 // Env holds the currently opened environment. 101 // This is set by PrepareOnce and BootstrapOnce. 102 Env environs.Environ 103 104 // ControllerStore holds the controller related information 105 // such as controllers, accounts, etc., used when preparing 106 // the environment. This is initialized by SetUpSuite. 107 ControllerStore jujuclient.ClientStore 108 109 // ControllerUUID is the uuid of the bootstrapped controller. 110 ControllerUUID string 111 112 // ProviderCallContext holds the context to be used to make 113 // calls to a cloud provider. 114 ProviderCallContext context.ProviderCallContext 115 116 // BootstrapContext holds the context to bootstrap a test environment. 117 BootstrapContext environs.BootstrapContext 118 119 prepared bool 120 bootstrapped bool 121 toolsStorage storage.Storage 122 } 123 124 func (t *LiveTests) SetUpSuite(c *gc.C) { 125 t.CleanupSuite.SetUpSuite(c) 126 t.TestDataSuite.SetUpSuite(c) 127 t.ControllerStore = jujuclient.NewMemStore() 128 t.PatchValue(&keys.JujuPublicKey, sstesting.SignedMetadataPublicKey) 129 130 // Setup the simplestreams bootstrap context. 131 ss := simplestreams.NewSimpleStreams(sstesting.TestDataSourceFactory()) 132 133 ctx := stdcontext.TODO() 134 ctx = stdcontext.WithValue(ctx, bootstrap.SimplestreamsFetcherContextKey, ss) 135 136 t.BootstrapContext = envtesting.BootstrapContext(ctx, c) 137 t.ProviderCallContext = context.NewCloudCallContext(ctx) 138 } 139 140 func (t *LiveTests) SetUpTest(c *gc.C) { 141 t.CleanupSuite.SetUpTest(c) 142 t.PatchValue(&jujuversion.Current, coretesting.FakeVersionNumber) 143 storageDir := c.MkDir() 144 baseURLPath := filepath.Join(storageDir, "tools") 145 t.DefaultBaseURL = utils.MakeFileURL(baseURLPath) 146 t.ToolsFixture.SetUpTest(c) 147 stor, err := filestorage.NewFileStorageWriter(storageDir) 148 c.Assert(err, jc.ErrorIsNil) 149 t.UploadFakeTools(c, stor, "released", "released") 150 t.toolsStorage = stor 151 t.CleanupSuite.PatchValue(&envtools.BundleTools, envtoolstesting.GetMockBundleTools(coretesting.FakeVersionNumber)) 152 } 153 154 func (t *LiveTests) TearDownSuite(c *gc.C) { 155 t.Destroy(c) 156 t.TestDataSuite.TearDownSuite(c) 157 t.CleanupSuite.TearDownSuite(c) 158 } 159 160 func (t *LiveTests) TearDownTest(c *gc.C) { 161 t.ToolsFixture.TearDownTest(c) 162 t.CleanupSuite.TearDownTest(c) 163 } 164 165 // PrepareOnce ensures that the environment is 166 // available and prepared. It sets t.Env appropriately. 167 func (t *LiveTests) PrepareOnce(c *gc.C) { 168 if t.prepared { 169 return 170 } 171 172 args := t.prepareForBootstrapParams(c) 173 e, err := bootstrap.PrepareController(false, t.BootstrapContext, t.ControllerStore, args) 174 c.Assert(err, gc.IsNil, gc.Commentf("preparing environ %#v", t.TestConfig)) 175 c.Assert(e, gc.NotNil) 176 t.Env = e.(environs.Environ) 177 t.prepared = true 178 t.ControllerUUID = coretesting.FakeControllerConfig().ControllerUUID() 179 } 180 181 func (t *LiveTests) prepareForBootstrapParams(c *gc.C) bootstrap.PrepareParams { 182 credential := t.Credential 183 if credential.AuthType() == "" { 184 credential = cloud.NewEmptyCredential() 185 } 186 return bootstrap.PrepareParams{ 187 ControllerConfig: coretesting.FakeControllerConfig(), 188 ModelConfig: t.TestConfig, 189 Cloud: environscloudspec.CloudSpec{ 190 Type: t.TestConfig["type"].(string), 191 Name: t.TestConfig["type"].(string), 192 Region: t.CloudRegion, 193 Endpoint: t.CloudEndpoint, 194 Credential: &credential, 195 }, 196 ControllerName: t.TestConfig["name"].(string), 197 AdminSecret: AdminSecret, 198 } 199 } 200 201 func (t *LiveTests) bootstrapParams() bootstrap.BootstrapParams { 202 credential := t.Credential 203 if credential.AuthType() == "" { 204 credential = cloud.NewEmptyCredential() 205 } 206 var regions []cloud.Region 207 if t.CloudRegion != "" { 208 regions = []cloud.Region{{ 209 Name: t.CloudRegion, 210 Endpoint: t.CloudEndpoint, 211 }} 212 } 213 return bootstrap.BootstrapParams{ 214 ControllerConfig: coretesting.FakeControllerConfig(), 215 Cloud: cloud.Cloud{ 216 Name: t.TestConfig["type"].(string), 217 Type: t.TestConfig["type"].(string), 218 AuthTypes: []cloud.AuthType{credential.AuthType()}, 219 Regions: regions, 220 Endpoint: t.CloudEndpoint, 221 }, 222 CloudRegion: t.CloudRegion, 223 CloudCredential: &credential, 224 CloudCredentialName: "credential", 225 AdminSecret: AdminSecret, 226 CAPrivateKey: coretesting.CAKey, 227 SupportedBootstrapBases: coretesting.FakeSupportedJujuBases, 228 } 229 } 230 231 func (t *LiveTests) BootstrapOnce(c *gc.C) { 232 if t.bootstrapped { 233 return 234 } 235 236 t.PrepareOnce(c) 237 // We only build and upload tools if there will be a state agent that 238 // we could connect to (actual live tests, rather than local-only) 239 cons := constraints.MustParse("mem=2G") 240 if t.CanOpenState { 241 ss := simplestreams.NewSimpleStreams(sstesting.TestDataSourceFactory()) 242 _, err := sync.Upload(ss, t.toolsStorage, "released", nil) 243 c.Assert(err, jc.ErrorIsNil) 244 } 245 args := t.bootstrapParams() 246 args.BootstrapConstraints = cons 247 args.ModelConstraints = cons 248 249 err := bootstrap.Bootstrap(t.BootstrapContext, t.Env, t.ProviderCallContext, args) 250 c.Assert(err, jc.ErrorIsNil) 251 t.bootstrapped = true 252 } 253 254 func (t *LiveTests) Destroy(c *gc.C) { 255 if t.Env == nil { 256 return 257 } 258 err := environs.Destroy(t.Env.Config().Name(), t.Env, t.ProviderCallContext, t.ControllerStore) 259 c.Assert(err, jc.ErrorIsNil) 260 t.bootstrapped = false 261 t.prepared = false 262 t.ControllerUUID = "" 263 t.Env = nil 264 } 265 266 func (t *LiveTests) TestPrechecker(c *gc.C) { 267 // All implementations of InstancePrechecker should 268 // return nil for empty constraints (excluding the 269 // manual provider). 270 t.PrepareOnce(c) 271 err := t.Env.PrecheckInstance(t.ProviderCallContext, 272 environs.PrecheckInstanceParams{ 273 Base: corebase.MakeDefaultBase("ubuntu", "22.04"), 274 }) 275 c.Assert(err, jc.ErrorIsNil) 276 } 277 278 // TestStartStop is similar to Tests.TestStartStop except 279 // that it does not assume a pristine environment. 280 func (t *LiveTests) TestStartStop(c *gc.C) { 281 t.BootstrapOnce(c) 282 283 inst, _ := jujutesting.AssertStartInstance(c, t.Env, t.ProviderCallContext, t.ControllerUUID, "0") 284 c.Assert(inst, gc.NotNil) 285 id0 := inst.Id() 286 287 insts, err := t.Env.Instances(t.ProviderCallContext, []instance.Id{id0, id0}) 288 c.Assert(err, jc.ErrorIsNil) 289 c.Assert(insts, gc.HasLen, 2) 290 c.Assert(insts[0].Id(), gc.Equals, id0) 291 c.Assert(insts[1].Id(), gc.Equals, id0) 292 293 // Asserting on the return of AllInstances makes the test fragile, 294 // as even comparing the before and after start values can be thrown 295 // off if other instances have been created or destroyed in the same 296 // time frame. Instead, just check the instance we created exists. 297 insts, err = t.Env.AllInstances(t.ProviderCallContext) 298 c.Assert(err, jc.ErrorIsNil) 299 found := false 300 for _, inst := range insts { 301 if inst.Id() == id0 { 302 c.Assert(found, gc.Equals, false, gc.Commentf("%v", insts)) 303 found = true 304 } 305 } 306 c.Assert(found, gc.Equals, true, gc.Commentf("expected %v in %v", inst, insts)) 307 308 addresses, err := jujutesting.WaitInstanceAddresses(t.Env, t.ProviderCallContext, inst.Id()) 309 c.Assert(err, jc.ErrorIsNil) 310 c.Assert(addresses, gc.Not(gc.HasLen), 0) 311 312 insts, err = t.Env.Instances(t.ProviderCallContext, []instance.Id{id0, ""}) 313 c.Assert(err, gc.Equals, environs.ErrPartialInstances) 314 c.Assert(insts, gc.HasLen, 2) 315 c.Check(insts[0].Id(), gc.Equals, id0) 316 c.Check(insts[1], gc.IsNil) 317 318 err = t.Env.StopInstances(t.ProviderCallContext, inst.Id()) 319 c.Assert(err, jc.ErrorIsNil) 320 321 // The machine may not be marked as shutting down 322 // immediately. Repeat a few times to ensure we get the error. 323 for a := t.Attempt.Start(); a.Next(); { 324 insts, err = t.Env.Instances(t.ProviderCallContext, []instance.Id{id0}) 325 if err != nil { 326 break 327 } 328 } 329 c.Assert(err, gc.Equals, environs.ErrNoInstances) 330 c.Assert(insts, gc.HasLen, 0) 331 } 332 333 func (t *LiveTests) TestPorts(c *gc.C) { 334 t.BootstrapOnce(c) 335 336 inst1, _ := jujutesting.AssertStartInstance(c, t.Env, t.ProviderCallContext, t.ControllerUUID, "1") 337 c.Assert(inst1, gc.NotNil) 338 defer func() { _ = t.Env.StopInstances(t.ProviderCallContext, inst1.Id()) }() 339 fwInst1, ok := inst1.(instances.InstanceFirewaller) 340 c.Assert(ok, gc.Equals, true) 341 342 rules, err := fwInst1.IngressRules(t.ProviderCallContext, "1") 343 c.Assert(err, jc.ErrorIsNil) 344 c.Assert(rules, gc.HasLen, 0) 345 346 inst2, _ := jujutesting.AssertStartInstance(c, t.Env, t.ProviderCallContext, t.ControllerUUID, "2") 347 c.Assert(inst2, gc.NotNil) 348 fwInst2, ok := inst2.(instances.InstanceFirewaller) 349 c.Assert(ok, gc.Equals, true) 350 rules, err = fwInst2.IngressRules(t.ProviderCallContext, "2") 351 c.Assert(err, jc.ErrorIsNil) 352 c.Assert(rules, gc.HasLen, 0) 353 defer func() { _ = t.Env.StopInstances(t.ProviderCallContext, inst2.Id()) }() 354 355 // Open some ports and check they're there. 356 err = fwInst1.OpenPorts(t.ProviderCallContext, 357 "1", firewall.IngressRules{ 358 firewall.NewIngressRule(network.MustParsePortRange("67/udp")), 359 firewall.NewIngressRule(network.MustParsePortRange("45/tcp")), 360 firewall.NewIngressRule(network.MustParsePortRange("80-100/tcp")), 361 }) 362 363 c.Assert(err, jc.ErrorIsNil) 364 rules, err = fwInst1.IngressRules(t.ProviderCallContext, "1") 365 c.Assert(err, jc.ErrorIsNil) 366 c.Assert( 367 rules, jc.DeepEquals, 368 firewall.IngressRules{ 369 firewall.NewIngressRule(network.MustParsePortRange("45/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 370 firewall.NewIngressRule(network.MustParsePortRange("80-100/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 371 firewall.NewIngressRule(network.MustParsePortRange("67/udp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 372 }, 373 ) 374 rules, err = fwInst2.IngressRules(t.ProviderCallContext, "2") 375 c.Assert(err, jc.ErrorIsNil) 376 c.Assert(rules, gc.HasLen, 0) 377 378 err = fwInst2.OpenPorts(t.ProviderCallContext, 379 "2", firewall.IngressRules{ 380 firewall.NewIngressRule(network.MustParsePortRange("89/tcp")), 381 firewall.NewIngressRule(network.MustParsePortRange("45/tcp")), 382 firewall.NewIngressRule(network.MustParsePortRange("20-30/tcp")), 383 }) 384 c.Assert(err, jc.ErrorIsNil) 385 386 // Check there's no crosstalk to another machine 387 rules, err = fwInst2.IngressRules(t.ProviderCallContext, "2") 388 c.Assert(err, jc.ErrorIsNil) 389 c.Assert( 390 rules, jc.DeepEquals, 391 firewall.IngressRules{ 392 firewall.NewIngressRule(network.MustParsePortRange("20-30/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 393 firewall.NewIngressRule(network.MustParsePortRange("45/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 394 firewall.NewIngressRule(network.MustParsePortRange("89/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 395 }, 396 ) 397 rules, err = fwInst1.IngressRules(t.ProviderCallContext, "1") 398 c.Assert(err, jc.ErrorIsNil) 399 c.Assert( 400 rules, jc.DeepEquals, 401 firewall.IngressRules{ 402 firewall.NewIngressRule(network.MustParsePortRange("45/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 403 firewall.NewIngressRule(network.MustParsePortRange("80-100/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 404 firewall.NewIngressRule(network.MustParsePortRange("67/udp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 405 }, 406 ) 407 408 // Check that opening the same port again is ok. 409 oldRules, err := fwInst2.IngressRules(t.ProviderCallContext, "2") 410 c.Assert(err, jc.ErrorIsNil) 411 err = fwInst2.OpenPorts(t.ProviderCallContext, 412 "2", firewall.IngressRules{ 413 firewall.NewIngressRule(network.MustParsePortRange("45/tcp")), 414 }) 415 c.Assert(err, jc.ErrorIsNil) 416 err = fwInst2.OpenPorts(t.ProviderCallContext, 417 "2", firewall.IngressRules{ 418 firewall.NewIngressRule(network.MustParsePortRange("20-30/tcp")), 419 }) 420 c.Assert(err, jc.ErrorIsNil) 421 rules, err = fwInst2.IngressRules(t.ProviderCallContext, "2") 422 c.Assert(err, jc.ErrorIsNil) 423 c.Assert(rules, jc.DeepEquals, oldRules) 424 425 // Check that opening the same port again and another port is ok. 426 err = fwInst2.OpenPorts(t.ProviderCallContext, 427 "2", firewall.IngressRules{ 428 firewall.NewIngressRule(network.MustParsePortRange("45/tcp")), 429 firewall.NewIngressRule(network.MustParsePortRange("99/tcp")), 430 }) 431 c.Assert(err, jc.ErrorIsNil) 432 rules, err = fwInst2.IngressRules(t.ProviderCallContext, "2") 433 c.Assert(err, jc.ErrorIsNil) 434 c.Assert( 435 rules, jc.DeepEquals, 436 firewall.IngressRules{ 437 firewall.NewIngressRule(network.MustParsePortRange("20-30/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 438 firewall.NewIngressRule(network.MustParsePortRange("45/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 439 firewall.NewIngressRule(network.MustParsePortRange("89/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 440 firewall.NewIngressRule(network.MustParsePortRange("99/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 441 }, 442 ) 443 err = fwInst2.ClosePorts(t.ProviderCallContext, 444 "2", firewall.IngressRules{ 445 firewall.NewIngressRule(network.MustParsePortRange("45/tcp")), 446 firewall.NewIngressRule(network.MustParsePortRange("99/tcp")), 447 firewall.NewIngressRule(network.MustParsePortRange("20-30/tcp")), 448 }) 449 c.Assert(err, jc.ErrorIsNil) 450 451 // Check that we can close ports and that there's no crosstalk. 452 rules, err = fwInst2.IngressRules(t.ProviderCallContext, "2") 453 c.Assert(err, jc.ErrorIsNil) 454 c.Assert( 455 rules, jc.DeepEquals, 456 firewall.IngressRules{ 457 firewall.NewIngressRule(network.MustParsePortRange("89/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 458 }, 459 ) 460 rules, err = fwInst1.IngressRules(t.ProviderCallContext, "1") 461 c.Assert(err, jc.ErrorIsNil) 462 c.Assert( 463 rules, jc.DeepEquals, 464 firewall.IngressRules{ 465 firewall.NewIngressRule(network.MustParsePortRange("45/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 466 firewall.NewIngressRule(network.MustParsePortRange("80-100/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 467 firewall.NewIngressRule(network.MustParsePortRange("67/udp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 468 }, 469 ) 470 471 // Check that we can close multiple ports. 472 err = fwInst1.ClosePorts(t.ProviderCallContext, 473 "1", firewall.IngressRules{ 474 firewall.NewIngressRule(network.MustParsePortRange("45/tcp")), 475 firewall.NewIngressRule(network.MustParsePortRange("67/udp")), 476 firewall.NewIngressRule(network.MustParsePortRange("80-100/tcp")), 477 }) 478 c.Assert(err, jc.ErrorIsNil) 479 rules, err = fwInst1.IngressRules(t.ProviderCallContext, "1") 480 c.Assert(err, jc.ErrorIsNil) 481 c.Assert(rules, gc.HasLen, 0) 482 483 // Check that we can close ports that aren't there. 484 err = fwInst2.ClosePorts(t.ProviderCallContext, 485 "2", firewall.IngressRules{ 486 firewall.NewIngressRule(network.MustParsePortRange("111/tcp")), 487 firewall.NewIngressRule(network.MustParsePortRange("222/udp")), 488 firewall.NewIngressRule(network.MustParsePortRange("600-700/tcp")), 489 }) 490 c.Assert(err, jc.ErrorIsNil) 491 rules, err = fwInst2.IngressRules(t.ProviderCallContext, "2") 492 c.Assert(err, jc.ErrorIsNil) 493 c.Assert( 494 rules, jc.DeepEquals, 495 firewall.IngressRules{ 496 firewall.NewIngressRule(network.MustParsePortRange("89/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 497 }, 498 ) 499 500 // Check errors when acting on environment. 501 fwEnv, ok := t.Env.(environs.Firewaller) 502 c.Assert(ok, gc.Equals, true) 503 err = fwEnv.OpenPorts(t.ProviderCallContext, firewall.IngressRules{firewall.NewIngressRule(network.MustParsePortRange("80/tcp"))}) 504 c.Assert(err, gc.ErrorMatches, `invalid firewall mode "instance" for opening ports on model`) 505 506 err = fwEnv.ClosePorts(t.ProviderCallContext, firewall.IngressRules{firewall.NewIngressRule(network.MustParsePortRange("80/tcp"))}) 507 c.Assert(err, gc.ErrorMatches, `invalid firewall mode "instance" for closing ports on model`) 508 509 _, err = fwEnv.IngressRules(t.ProviderCallContext) 510 c.Assert(err, gc.ErrorMatches, `invalid firewall mode "instance" for retrieving ingress rules from model`) 511 } 512 513 func (t *LiveTests) TestGlobalPorts(c *gc.C) { 514 t.BootstrapOnce(c) 515 516 // Change configuration. 517 oldConfig := t.Env.Config() 518 defer func() { 519 err := t.Env.SetConfig(oldConfig) 520 c.Assert(err, jc.ErrorIsNil) 521 }() 522 523 attrs := t.Env.Config().AllAttrs() 524 attrs["firewall-mode"] = config.FwGlobal 525 newConfig, err := t.Env.Config().Apply(attrs) 526 c.Assert(err, jc.ErrorIsNil) 527 err = t.Env.SetConfig(newConfig) 528 c.Assert(err, jc.ErrorIsNil) 529 530 // Create instances and check open ports on both instances. 531 inst1, _ := jujutesting.AssertStartInstance(c, t.Env, t.ProviderCallContext, t.ControllerUUID, "1") 532 defer func() { _ = t.Env.StopInstances(t.ProviderCallContext, inst1.Id()) }() 533 534 fwEnv, ok := t.Env.(environs.Firewaller) 535 c.Assert(ok, gc.Equals, true) 536 537 rules, err := fwEnv.IngressRules(t.ProviderCallContext) 538 c.Assert(err, jc.ErrorIsNil) 539 c.Assert(rules, gc.HasLen, 0) 540 541 inst2, _ := jujutesting.AssertStartInstance(c, t.Env, t.ProviderCallContext, t.ControllerUUID, "2") 542 rules, err = fwEnv.IngressRules(t.ProviderCallContext) 543 c.Assert(err, jc.ErrorIsNil) 544 c.Assert(rules, gc.HasLen, 0) 545 defer func() { _ = t.Env.StopInstances(t.ProviderCallContext, inst2.Id()) }() 546 547 err = fwEnv.OpenPorts(t.ProviderCallContext, 548 firewall.IngressRules{ 549 firewall.NewIngressRule(network.MustParsePortRange("67/udp")), 550 firewall.NewIngressRule(network.MustParsePortRange("45/tcp")), 551 firewall.NewIngressRule(network.MustParsePortRange("89/tcp")), 552 firewall.NewIngressRule(network.MustParsePortRange("99/tcp")), 553 firewall.NewIngressRule(network.MustParsePortRange("100-110/tcp")), 554 }) 555 c.Assert(err, jc.ErrorIsNil) 556 557 rules, err = fwEnv.IngressRules(t.ProviderCallContext) 558 c.Assert(err, jc.ErrorIsNil) 559 c.Assert( 560 rules, jc.DeepEquals, 561 firewall.IngressRules{ 562 firewall.NewIngressRule(network.MustParsePortRange("45/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 563 firewall.NewIngressRule(network.MustParsePortRange("89/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 564 firewall.NewIngressRule(network.MustParsePortRange("99/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 565 firewall.NewIngressRule(network.MustParsePortRange("100-110/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 566 firewall.NewIngressRule(network.MustParsePortRange("67/udp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 567 }, 568 ) 569 570 // Check closing some ports. 571 err = fwEnv.ClosePorts(t.ProviderCallContext, 572 firewall.IngressRules{ 573 firewall.NewIngressRule(network.MustParsePortRange("99/tcp")), 574 firewall.NewIngressRule(network.MustParsePortRange("67/udp")), 575 }) 576 c.Assert(err, jc.ErrorIsNil) 577 578 rules, err = fwEnv.IngressRules(t.ProviderCallContext) 579 c.Assert(err, jc.ErrorIsNil) 580 c.Assert( 581 rules, jc.DeepEquals, 582 firewall.IngressRules{ 583 firewall.NewIngressRule(network.MustParsePortRange("45/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 584 firewall.NewIngressRule(network.MustParsePortRange("89/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 585 firewall.NewIngressRule(network.MustParsePortRange("100-110/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 586 }, 587 ) 588 589 // Check that we can close ports that aren't there. 590 err = fwEnv.ClosePorts(t.ProviderCallContext, 591 firewall.IngressRules{ 592 firewall.NewIngressRule(network.MustParsePortRange("111/tcp")), 593 firewall.NewIngressRule(network.MustParsePortRange("222/udp")), 594 firewall.NewIngressRule(network.MustParsePortRange("2000-2500/tcp")), 595 }) 596 c.Assert(err, jc.ErrorIsNil) 597 598 rules, err = fwEnv.IngressRules(t.ProviderCallContext) 599 c.Assert(err, jc.ErrorIsNil) 600 c.Assert( 601 rules, jc.DeepEquals, 602 firewall.IngressRules{ 603 firewall.NewIngressRule(network.MustParsePortRange("45/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 604 firewall.NewIngressRule(network.MustParsePortRange("89/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 605 firewall.NewIngressRule(network.MustParsePortRange("100-110/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 606 }, 607 ) 608 609 fwInst1, ok := inst1.(instances.InstanceFirewaller) 610 c.Assert(ok, gc.Equals, true) 611 // Check errors when acting on instances. 612 err = fwInst1.OpenPorts(t.ProviderCallContext, 613 "1", firewall.IngressRules{firewall.NewIngressRule(network.MustParsePortRange("80/tcp"))}) 614 c.Assert(err, gc.ErrorMatches, `invalid firewall mode "global" for opening ports on instance`) 615 616 err = fwInst1.ClosePorts(t.ProviderCallContext, 617 "1", firewall.IngressRules{firewall.NewIngressRule(network.MustParsePortRange("80/tcp"))}) 618 c.Assert(err, gc.ErrorMatches, `invalid firewall mode "global" for closing ports on instance`) 619 620 _, err = fwInst1.IngressRules(t.ProviderCallContext, "1") 621 c.Assert(err, gc.ErrorMatches, `invalid firewall mode "global" for retrieving ingress rules from instance`) 622 } 623 624 func (t *LiveTests) TestModelPorts(c *gc.C) { 625 t.BootstrapOnce(c) 626 627 fwModelEnv, ok := t.Env.(models.ModelFirewaller) 628 c.Assert(ok, gc.Equals, true) 629 630 rules, err := fwModelEnv.ModelIngressRules(t.ProviderCallContext) 631 c.Assert(err, jc.ErrorIsNil) 632 c.Assert(rules, jc.SameContents, firewall.IngressRules{ 633 firewall.NewIngressRule(network.MustParsePortRange("22/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 634 // TODO: extend tests to check the api port isn't on hosted models. 635 firewall.NewIngressRule(network.MustParsePortRange(strconv.Itoa(coretesting.FakeControllerConfig().APIPort())), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 636 }) 637 638 err = fwModelEnv.OpenModelPorts(t.ProviderCallContext, 639 firewall.IngressRules{ 640 firewall.NewIngressRule(network.MustParsePortRange("67/udp")), 641 firewall.NewIngressRule(network.MustParsePortRange("45/tcp")), 642 firewall.NewIngressRule(network.MustParsePortRange("100-110/tcp")), 643 }) 644 c.Assert(err, jc.ErrorIsNil) 645 646 rules, err = fwModelEnv.ModelIngressRules(t.ProviderCallContext) 647 c.Assert(err, jc.ErrorIsNil) 648 c.Assert(rules, jc.SameContents, firewall.IngressRules{ 649 firewall.NewIngressRule(network.MustParsePortRange("22/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 650 // TODO: extend tests to check the api port isn't on hosted models. 651 firewall.NewIngressRule(network.MustParsePortRange(strconv.Itoa(coretesting.FakeControllerConfig().APIPort())), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 652 firewall.NewIngressRule(network.MustParsePortRange("45/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 653 firewall.NewIngressRule(network.MustParsePortRange("100-110/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 654 firewall.NewIngressRule(network.MustParsePortRange("67/udp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 655 }) 656 657 // Check closing some ports. 658 err = fwModelEnv.CloseModelPorts(t.ProviderCallContext, 659 firewall.IngressRules{ 660 firewall.NewIngressRule(network.MustParsePortRange("45/tcp")), 661 firewall.NewIngressRule(network.MustParsePortRange("67/udp")), 662 }) 663 c.Assert(err, jc.ErrorIsNil) 664 665 rules, err = fwModelEnv.ModelIngressRules(t.ProviderCallContext) 666 c.Assert(err, jc.ErrorIsNil) 667 c.Assert(rules, jc.SameContents, firewall.IngressRules{ 668 firewall.NewIngressRule(network.MustParsePortRange("22/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 669 // TODO: extend tests to check the api port isn't on hosted models. 670 firewall.NewIngressRule(network.MustParsePortRange(strconv.Itoa(coretesting.FakeControllerConfig().APIPort())), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 671 firewall.NewIngressRule(network.MustParsePortRange("100-110/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 672 }) 673 674 // Check that we can close ports that aren't there. 675 err = fwModelEnv.CloseModelPorts(t.ProviderCallContext, 676 firewall.IngressRules{ 677 firewall.NewIngressRule(network.MustParsePortRange("111/tcp")), 678 firewall.NewIngressRule(network.MustParsePortRange("222/udp")), 679 firewall.NewIngressRule(network.MustParsePortRange("2000-2500/tcp")), 680 }) 681 c.Assert(err, jc.ErrorIsNil) 682 683 rules, err = fwModelEnv.ModelIngressRules(t.ProviderCallContext) 684 c.Assert(err, jc.ErrorIsNil) 685 c.Assert(rules, jc.SameContents, firewall.IngressRules{ 686 firewall.NewIngressRule(network.MustParsePortRange("22/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 687 // TODO: extend tests to check the api port isn't on hosted models. 688 firewall.NewIngressRule(network.MustParsePortRange(strconv.Itoa(coretesting.FakeControllerConfig().APIPort())), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 689 firewall.NewIngressRule(network.MustParsePortRange("100-110/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 690 }) 691 692 // Cleanup 693 err = fwModelEnv.CloseModelPorts(t.ProviderCallContext, firewall.IngressRules{ 694 firewall.NewIngressRule(network.MustParsePortRange("100-110/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 695 }) 696 c.Assert(err, jc.ErrorIsNil) 697 } 698 699 func (t *LiveTests) TestBootstrapMultiple(c *gc.C) { 700 // bootstrap.Bootstrap no longer raises errors if the environment is 701 // already up, this has been moved into the bootstrap command. 702 t.BootstrapOnce(c) 703 704 c.Logf("destroy env") 705 env := t.Env 706 t.Destroy(c) 707 err := env.Destroy(t.ProviderCallContext) // Again, should work fine and do nothing. 708 c.Assert(err, jc.ErrorIsNil) 709 710 // check that we can bootstrap after destroy 711 t.BootstrapOnce(c) 712 } 713 714 func (t *LiveTests) TestBootstrapAndDeploy(c *gc.C) { 715 if !t.CanOpenState || !t.HasProvisioner { 716 c.Skip(fmt.Sprintf("skipping provisioner test, CanOpenState: %v, HasProvisioner: %v", t.CanOpenState, t.HasProvisioner)) 717 } 718 t.BootstrapOnce(c) 719 720 // TODO(niemeyer): Stop growing this kitchen sink test and split it into proper parts. 721 722 c.Logf("opening state") 723 st := t.Env.(jujutesting.GetStater).GetStateInAPIServer() 724 725 model, err := st.Model() 726 c.Assert(err, jc.ErrorIsNil) 727 owner := model.Owner() 728 729 c.Logf("opening API connection") 730 controllerCfg, err := st.ControllerConfig() 731 c.Assert(err, jc.ErrorIsNil) 732 caCert, _ := controllerCfg.CACert() 733 apiInfo, err := environs.APIInfo(t.ProviderCallContext, model.Tag().Id(), model.Tag().Id(), caCert, controllerCfg.APIPort(), t.Env) 734 c.Assert(err, jc.ErrorIsNil) 735 apiInfo.Tag = owner 736 apiInfo.Password = AdminSecret 737 apiState, err := api.Open(apiInfo, api.DefaultDialOpts()) 738 c.Assert(err, jc.ErrorIsNil) 739 defer apiState.Close() 740 741 // Check that the agent version has made it through the 742 // bootstrap process (it's optional in the config.Config) 743 cfg, err := model.ModelConfig() 744 c.Assert(err, jc.ErrorIsNil) 745 agentVersion, ok := cfg.AgentVersion() 746 c.Check(ok, jc.IsTrue) 747 c.Check(agentVersion, gc.Equals, jujuversion.Current) 748 749 // Check that the constraints have been set in the environment. 750 cons, err := st.ModelConstraints() 751 c.Assert(err, jc.ErrorIsNil) 752 c.Assert(cons.String(), gc.Equals, "mem=2048M") 753 754 // Wait for machine agent to come up on the bootstrap 755 // machine and find the deployed series from that. 756 m0, err := st.Machine("0") 757 c.Assert(err, jc.ErrorIsNil) 758 759 instId0, err := m0.InstanceId() 760 c.Assert(err, jc.ErrorIsNil) 761 762 // Check that the API connection is working. 763 status, err := apiclient.NewClient(apiState, coretesting.NoopLogger{}).Status(nil) 764 c.Assert(err, jc.ErrorIsNil) 765 c.Assert(status.Machines["0"].InstanceId, gc.Equals, string(instId0)) 766 767 mw0 := newMachineToolWaiter(m0) 768 defer func() { _ = mw0.Stop() }() 769 770 // Controllers always run on Ubuntu. 771 expectedVersion := version.Binary{ 772 Number: jujuversion.Current, 773 Arch: arch.HostArch(), 774 Release: "ubuntu", 775 } 776 777 mtools0 := waitAgentTools(c, mw0, expectedVersion) 778 779 // Create a new application and deploy a unit of it. 780 c.Logf("deploying application") 781 ch := testcharms.Repo.ClonedDir(c.MkDir(), "dummy") 782 sch, err := jujutesting.PutCharm(st, charm.MustParseURL("local:dummy"), ch) 783 c.Assert(err, jc.ErrorIsNil) 784 svc, err := st.AddApplication(state.AddApplicationArgs{Name: "dummy", Charm: sch}) 785 c.Assert(err, jc.ErrorIsNil) 786 unit, err := svc.AddUnit(state.AddUnitParams{}) 787 c.Assert(err, jc.ErrorIsNil) 788 err = st.AssignUnit(unit, state.AssignCleanEmpty) 789 c.Assert(err, jc.ErrorIsNil) 790 791 // Wait for the unit's machine and associated agent to come up 792 // and announce itself. 793 mid1, err := unit.AssignedMachineId() 794 c.Assert(err, jc.ErrorIsNil) 795 m1, err := st.Machine(mid1) 796 c.Assert(err, jc.ErrorIsNil) 797 mw1 := newMachineToolWaiter(m1) 798 defer func() { _ = mw1.Stop() }() 799 waitAgentTools(c, mw1, mtools0.Version) 800 801 err = m1.Refresh() 802 c.Assert(err, jc.ErrorIsNil) 803 instId1, err := m1.InstanceId() 804 c.Assert(err, jc.ErrorIsNil) 805 uw := newUnitToolWaiter(unit) 806 defer func() { _ = uw.Stop() }() 807 utools := waitAgentTools(c, uw, expectedVersion) 808 809 // Check that we can upgrade the environment. 810 newVersion := utools.Version 811 newVersion.Patch++ 812 t.checkUpgrade(c, st, newVersion, mw0, mw1, uw) 813 814 // BUG(niemeyer): Logic below is very much wrong. Must be: 815 // 816 // 1. EnsureDying on the unit and EnsureDying on the machine 817 // 2. Unit dies by itself 818 // 3. Machine removes dead unit 819 // 4. Machine dies by itself 820 // 5. Provisioner removes dead machine 821 // 822 823 // Now remove the unit and its assigned machine and 824 // check that the PA removes it. 825 c.Logf("removing unit") 826 err = unit.Destroy() 827 c.Assert(err, jc.ErrorIsNil) 828 829 // Wait until unit is dead 830 uwatch := unit.Watch() 831 defer func() { _ = uwatch.Stop() }() 832 for unit.Life() != state.Dead { 833 c.Logf("waiting for unit change") 834 <-uwatch.Changes() 835 err := unit.Refresh() 836 c.Logf("refreshed; err %v", err) 837 if errors.IsNotFound(err) { 838 c.Logf("unit has been removed") 839 break 840 } 841 c.Assert(err, jc.ErrorIsNil) 842 } 843 for { 844 c.Logf("destroying machine") 845 err := m1.Destroy() 846 if err == nil { 847 break 848 } 849 c.Assert(errors.Is(err, stateerrors.HasAssignedUnitsError), jc.IsTrue) 850 time.Sleep(5 * time.Second) 851 err = m1.Refresh() 852 if errors.IsNotFound(err) { 853 break 854 } 855 c.Assert(err, jc.ErrorIsNil) 856 } 857 c.Logf("waiting for instance to be removed") 858 t.assertStopInstance(c, t.Env, instId1) 859 } 860 861 type tooler interface { 862 Life() state.Life 863 AgentTools() (*coretools.Tools, error) 864 Refresh() error 865 String() string 866 } 867 868 type watcher interface { 869 Stop() error 870 Err() error 871 } 872 873 type toolsWaiter struct { 874 lastTools *coretools.Tools 875 // changes is a chan of struct{} so that it can 876 // be used with different kinds of entity watcher. 877 changes chan struct{} 878 watcher watcher 879 tooler tooler 880 } 881 882 func newMachineToolWaiter(m *state.Machine) *toolsWaiter { 883 w := m.Watch() 884 waiter := &toolsWaiter{ 885 changes: make(chan struct{}, 1), 886 watcher: w, 887 tooler: m, 888 } 889 go func() { 890 for range w.Changes() { 891 waiter.changes <- struct{}{} 892 } 893 close(waiter.changes) 894 }() 895 return waiter 896 } 897 898 func newUnitToolWaiter(u *state.Unit) *toolsWaiter { 899 w := u.Watch() 900 waiter := &toolsWaiter{ 901 changes: make(chan struct{}, 1), 902 watcher: w, 903 tooler: u, 904 } 905 go func() { 906 for range w.Changes() { 907 waiter.changes <- struct{}{} 908 } 909 close(waiter.changes) 910 }() 911 return waiter 912 } 913 914 func (w *toolsWaiter) Stop() error { 915 return w.watcher.Stop() 916 } 917 918 // NextTools returns the next changed tools, waiting 919 // until the tools are actually set. 920 func (w *toolsWaiter) NextTools(c *gc.C) (*coretools.Tools, error) { 921 for range w.changes { 922 err := w.tooler.Refresh() 923 if err != nil { 924 return nil, fmt.Errorf("cannot refresh: %v", err) 925 } 926 if w.tooler.Life() == state.Dead { 927 return nil, fmt.Errorf("object is dead") 928 } 929 tools, err := w.tooler.AgentTools() 930 if errors.IsNotFound(err) { 931 c.Logf("tools not yet set") 932 continue 933 } 934 if err != nil { 935 return nil, err 936 } 937 changed := w.lastTools == nil || *tools != *w.lastTools 938 w.lastTools = tools 939 if changed { 940 return tools, nil 941 } 942 c.Logf("found same tools") 943 } 944 return nil, fmt.Errorf("watcher closed prematurely: %v", w.watcher.Err()) 945 } 946 947 // waitAgentTools waits for the given agent 948 // to start and returns the tools that it is running. 949 func waitAgentTools(c *gc.C, w *toolsWaiter, expect version.Binary) *coretools.Tools { 950 c.Logf("waiting for %v to signal agent version", w.tooler.String()) 951 tools, err := w.NextTools(c) 952 c.Assert(err, jc.ErrorIsNil) 953 c.Check(tools.Version, gc.Equals, expect) 954 return tools 955 } 956 957 // checkUpgrade sets the environment agent version and checks that 958 // all the provided watchers upgrade to the requested version. 959 func (t *LiveTests) checkUpgrade(c *gc.C, st *state.State, newVersion version.Binary, waiters ...*toolsWaiter) { 960 c.Logf("putting testing version of juju tools") 961 ss := simplestreams.NewSimpleStreams(sstesting.TestDataSourceFactory()) 962 upgradeTools, err := sync.Upload( 963 ss, t.toolsStorage, "released", 964 func(version.Number) version.Number { return newVersion.Number }, 965 ) 966 c.Assert(err, jc.ErrorIsNil) 967 968 // Check that the put version really is the version we expect. 969 c.Assert(upgradeTools.Version, gc.Equals, newVersion) 970 err = statetesting.SetAgentVersion(st, newVersion.Number) 971 c.Assert(err, jc.ErrorIsNil) 972 973 for i, w := range waiters { 974 c.Logf("waiting for upgrade of %d: %v", i, w.tooler.String()) 975 976 waitAgentTools(c, w, newVersion) 977 c.Logf("upgrade %d successful", i) 978 } 979 } 980 981 // TODO(katco): 2016-08-09: lp:1611427 982 var waitAgent = utils.AttemptStrategy{ 983 Total: 30 * time.Second, 984 Delay: 1 * time.Second, 985 } 986 987 func (t *LiveTests) assertStopInstance(c *gc.C, env environs.Environ, instId instance.Id) { 988 var err error 989 for a := waitAgent.Start(); a.Next(); { 990 _, err = t.Env.Instances(t.ProviderCallContext, []instance.Id{instId}) 991 if err == nil { 992 continue 993 } 994 if err == environs.ErrNoInstances { 995 return 996 } 997 c.Logf("error from Instances: %v", err) 998 } 999 c.Fatalf("provisioner failed to stop machine after %v", waitAgent.Total) 1000 } 1001 1002 func (t *LiveTests) TestStartInstanceWithEmptyNonceFails(c *gc.C) { 1003 // Check that we get a consistent error when asking for an instance without 1004 // a valid machine config. 1005 machineId := "4" 1006 apiInfo := jujutesting.FakeAPIInfo(machineId) 1007 instanceConfig, err := instancecfg.NewInstanceConfig(coretesting.ControllerTag, machineId, "", 1008 "released", corebase.MakeDefaultBase("ubuntu", "22.04"), apiInfo) 1009 c.Assert(err, jc.ErrorIsNil) 1010 1011 t.PrepareOnce(c) 1012 possibleTools := coretools.List(envtesting.AssertUploadFakeToolsVersions( 1013 c, t.toolsStorage, "released", "released", version.MustParseBinary("5.4.5-ubuntu-amd64"), 1014 )) 1015 fakeCallback := func(_ status.Status, _ string, _ map[string]interface{}) error { 1016 return nil 1017 } 1018 params := environs.StartInstanceParams{ 1019 ControllerUUID: coretesting.ControllerTag.Id(), 1020 Tools: possibleTools, 1021 InstanceConfig: instanceConfig, 1022 StatusCallback: fakeCallback, 1023 } 1024 err = jujutesting.SetImageMetadata( 1025 t.Env, 1026 simplestreams.NewSimpleStreams(sstesting.TestDataSourceFactory()), 1027 []string{"22.04"}, 1028 []string{"amd64"}, 1029 ¶ms.ImageMetadata, 1030 ) 1031 c.Check(err, jc.ErrorIsNil) 1032 result, err := t.Env.StartInstance(t.ProviderCallContext, params) 1033 if result != nil && result.Instance != nil { 1034 err := t.Env.StopInstances(t.ProviderCallContext, result.Instance.Id()) 1035 c.Check(err, jc.ErrorIsNil) 1036 } 1037 c.Assert(result, gc.IsNil) 1038 c.Assert(err, gc.ErrorMatches, ".*missing machine nonce") 1039 } 1040 1041 func (t *LiveTests) TestBootstrapWithDefaultSeries(c *gc.C) { 1042 if !t.HasProvisioner { 1043 c.Skip("HasProvisioner is false; cannot test deployment") 1044 } 1045 1046 current := coretesting.CurrentVersion() 1047 other := current 1048 other.Release = "quantal" 1049 1050 dummyCfg := dummy.SampleConfig().Merge(coretesting.Attrs{ 1051 "controller": false, 1052 "name": "dummy storage", 1053 }) 1054 args := t.prepareForBootstrapParams(c) 1055 args.ModelConfig = dummyCfg 1056 e, err := bootstrap.PrepareController(false, t.BootstrapContext, 1057 jujuclient.NewMemStore(), 1058 args, 1059 ) 1060 c.Assert(err, jc.ErrorIsNil) 1061 defer func() { _ = e.(environs.Environ).Destroy(t.ProviderCallContext) }() 1062 1063 t.Destroy(c) 1064 1065 attrs := t.TestConfig.Merge(coretesting.Attrs{ 1066 "name": "livetests", 1067 "default-series": "quantal", 1068 }) 1069 args.ModelConfig = attrs 1070 env, err := bootstrap.PrepareController(false, t.BootstrapContext, 1071 t.ControllerStore, 1072 args) 1073 c.Assert(err, jc.ErrorIsNil) 1074 defer func() { _ = environs.Destroy("livetests", env, t.ProviderCallContext, t.ControllerStore) }() 1075 1076 err = bootstrap.Bootstrap(t.BootstrapContext, env, t.ProviderCallContext, t.bootstrapParams()) 1077 c.Assert(err, jc.ErrorIsNil) 1078 1079 st := t.Env.(jujutesting.GetStater).GetStateInAPIServer() 1080 // Wait for machine agent to come up on the bootstrap 1081 // machine and ensure it deployed the proper series. 1082 m0, err := st.Machine("0") 1083 c.Assert(err, jc.ErrorIsNil) 1084 mw0 := newMachineToolWaiter(m0) 1085 defer func() { _ = mw0.Stop() }() 1086 1087 waitAgentTools(c, mw0, other) 1088 } 1089 1090 func (t *LiveTests) TestIngressRulesWithPartiallyMatchingCIDRs(c *gc.C) { 1091 t.BootstrapOnce(c) 1092 1093 inst1, _ := jujutesting.AssertStartInstance(c, t.Env, t.ProviderCallContext, t.ControllerUUID, "1") 1094 c.Assert(inst1, gc.NotNil) 1095 defer func() { _ = t.Env.StopInstances(t.ProviderCallContext, inst1.Id()) }() 1096 fwInst1, ok := inst1.(instances.InstanceFirewaller) 1097 c.Assert(ok, gc.Equals, true) 1098 1099 rules, err := fwInst1.IngressRules(t.ProviderCallContext, "1") 1100 c.Assert(err, jc.ErrorIsNil) 1101 c.Assert(rules, gc.HasLen, 0) 1102 1103 // Open ports with different CIDRs. Check that rules with same port range 1104 // get merged. 1105 err = fwInst1.OpenPorts(t.ProviderCallContext, 1106 "1", firewall.IngressRules{ 1107 firewall.NewIngressRule(network.MustParsePortRange("42/tcp"), firewall.AllNetworksIPV4CIDR), 1108 firewall.NewIngressRule(network.MustParsePortRange("42/tcp"), "10.0.0.0/24"), 1109 firewall.NewIngressRule(network.MustParsePortRange("80/tcp")), // open to 0.0.0.0/0 1110 }) 1111 1112 c.Assert(err, jc.ErrorIsNil) 1113 rules, err = fwInst1.IngressRules(t.ProviderCallContext, "1") 1114 c.Assert(err, jc.ErrorIsNil) 1115 c.Assert( 1116 rules, jc.DeepEquals, 1117 firewall.IngressRules{ 1118 firewall.NewIngressRule(network.MustParsePortRange("42/tcp"), firewall.AllNetworksIPV4CIDR, "10.0.0.0/24"), 1119 firewall.NewIngressRule(network.MustParsePortRange("80/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 1120 }, 1121 ) 1122 1123 // Open same port with different CIDRs and check that the CIDR gets 1124 // appended to the existing rule's CIDR list. 1125 err = fwInst1.OpenPorts(t.ProviderCallContext, 1126 "1", firewall.IngressRules{ 1127 firewall.NewIngressRule(network.MustParsePortRange("42/tcp"), "192.168.0.0/24"), 1128 }) 1129 1130 c.Assert(err, jc.ErrorIsNil) 1131 rules, err = fwInst1.IngressRules(t.ProviderCallContext, "1") 1132 c.Assert(err, jc.ErrorIsNil) 1133 c.Assert( 1134 rules, jc.DeepEquals, 1135 firewall.IngressRules{ 1136 firewall.NewIngressRule(network.MustParsePortRange("42/tcp"), firewall.AllNetworksIPV4CIDR, "10.0.0.0/24", "192.168.0.0/24"), 1137 firewall.NewIngressRule(network.MustParsePortRange("80/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 1138 }, 1139 ) 1140 1141 // Close port on a subset of the CIDRs and ensure that that CIDR gets 1142 // removed from the ingress rules 1143 err = fwInst1.ClosePorts(t.ProviderCallContext, 1144 "1", firewall.IngressRules{ 1145 firewall.NewIngressRule(network.MustParsePortRange("42/tcp"), "192.168.0.0/24"), 1146 }) 1147 1148 c.Assert(err, jc.ErrorIsNil) 1149 rules, err = fwInst1.IngressRules(t.ProviderCallContext, "1") 1150 c.Assert(err, jc.ErrorIsNil) 1151 c.Assert( 1152 rules, jc.DeepEquals, 1153 firewall.IngressRules{ 1154 firewall.NewIngressRule(network.MustParsePortRange("42/tcp"), firewall.AllNetworksIPV4CIDR, "10.0.0.0/24"), 1155 firewall.NewIngressRule(network.MustParsePortRange("80/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 1156 }, 1157 ) 1158 1159 // Remove all CIDRs from the rule and check that rules without CIDRs 1160 // get dropped. 1161 err = fwInst1.ClosePorts(t.ProviderCallContext, 1162 "1", firewall.IngressRules{ 1163 firewall.NewIngressRule(network.MustParsePortRange("42/tcp"), firewall.AllNetworksIPV4CIDR, "10.0.0.0/24"), 1164 }) 1165 1166 c.Assert(err, jc.ErrorIsNil) 1167 rules, err = fwInst1.IngressRules(t.ProviderCallContext, "1") 1168 c.Assert(err, jc.ErrorIsNil) 1169 c.Assert( 1170 rules, jc.DeepEquals, 1171 firewall.IngressRules{ 1172 firewall.NewIngressRule(network.MustParsePortRange("80/tcp"), firewall.AllNetworksIPV4CIDR, firewall.AllNetworksIPV6CIDR), 1173 }, 1174 ) 1175 }