github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/provider/azure/instance_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package azure_test 5 6 import ( 7 stdcontext "context" 8 "net/http" 9 "path" 10 11 "github.com/Azure/azure-sdk-for-go/sdk/azcore" 12 "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" 13 "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v2" 14 "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork" 15 "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources" 16 jc "github.com/juju/testing/checkers" 17 gc "gopkg.in/check.v1" 18 19 "github.com/juju/juju/core/instance" 20 corenetwork "github.com/juju/juju/core/network" 21 "github.com/juju/juju/core/network/firewall" 22 "github.com/juju/juju/core/status" 23 "github.com/juju/juju/environs" 24 "github.com/juju/juju/environs/context" 25 "github.com/juju/juju/environs/instances" 26 "github.com/juju/juju/provider/azure" 27 "github.com/juju/juju/provider/azure/internal/azuretesting" 28 "github.com/juju/juju/testing" 29 ) 30 31 type instanceSuite struct { 32 testing.BaseSuite 33 34 provider environs.EnvironProvider 35 requests []*http.Request 36 sender azuretesting.Senders 37 env environs.Environ 38 deployments []*armresources.DeploymentExtended 39 vms []*armcompute.VirtualMachine 40 networkInterfaces []*armnetwork.Interface 41 publicIPAddresses []*armnetwork.PublicIPAddress 42 43 callCtx *context.CloudCallContext 44 invalidteCredential bool 45 } 46 47 var _ = gc.Suite(&instanceSuite{}) 48 49 func (s *instanceSuite) SetUpTest(c *gc.C) { 50 s.BaseSuite.SetUpTest(c) 51 s.provider = newProvider(c, azure.ProviderConfig{ 52 Sender: &s.sender, 53 RequestInspector: &azuretesting.RequestRecorderPolicy{Requests: &s.requests}, 54 CreateTokenCredential: func(appId, appPassword, tenantID string, opts azcore.ClientOptions) (azcore.TokenCredential, error) { 55 return &azuretesting.FakeCredential{}, nil 56 }, 57 }) 58 s.env = openEnviron(c, s.provider, &s.sender) 59 s.sender = nil 60 s.requests = nil 61 s.networkInterfaces = []*armnetwork.Interface{ 62 makeNetworkInterface("nic-0", "machine-0"), 63 } 64 s.publicIPAddresses = nil 65 s.deployments = []*armresources.DeploymentExtended{ 66 makeDeployment("machine-0", armresources.ProvisioningStateSucceeded), 67 makeDeployment("machine-1", armresources.ProvisioningStateCreating), 68 } 69 s.vms = []*armcompute.VirtualMachine{{ 70 Name: to.Ptr("machine-0"), 71 Tags: map[string]*string{ 72 "juju-controller-uuid": to.Ptr(testing.ControllerTag.Id()), 73 "juju-model-uuid": to.Ptr(testing.ModelTag.Id()), 74 "juju-is-controller": to.Ptr("true"), 75 }, 76 Properties: &armcompute.VirtualMachineProperties{ 77 ProvisioningState: to.Ptr("Succeeded")}, 78 }} 79 s.callCtx = &context.CloudCallContext{ 80 Context: stdcontext.TODO(), 81 InvalidateCredentialFunc: func(string) error { 82 s.invalidteCredential = true 83 return nil 84 }, 85 } 86 } 87 88 func makeDeployment(name string, provisioningState armresources.ProvisioningState) *armresources.DeploymentExtended { 89 dependsOn := []*armresources.BasicDependency{{ 90 ResourceType: to.Ptr("Microsoft.Compute/availabilitySets"), 91 ResourceName: to.Ptr("mysql"), 92 }} 93 dependencies := []*armresources.Dependency{{ 94 ResourceType: to.Ptr("Microsoft.Compute/virtualMachines"), 95 DependsOn: dependsOn, 96 }} 97 return &armresources.DeploymentExtended{ 98 Name: to.Ptr(name), 99 Properties: &armresources.DeploymentPropertiesExtended{ 100 ProvisioningState: to.Ptr(provisioningState), 101 Dependencies: dependencies, 102 }, 103 Tags: map[string]*string{ 104 "juju-model-uuid": to.Ptr(testing.ModelTag.Id()), 105 }, 106 } 107 } 108 109 func makeNetworkInterface(nicName, vmName string, ipConfigurations ...*armnetwork.InterfaceIPConfiguration) *armnetwork.Interface { 110 tags := map[string]*string{"juju-machine-name": &vmName} 111 return &armnetwork.Interface{ 112 Name: to.Ptr(nicName), 113 Tags: tags, 114 Properties: &armnetwork.InterfacePropertiesFormat{ 115 IPConfigurations: ipConfigurations, 116 Primary: to.Ptr(true), 117 }, 118 } 119 } 120 121 func makeIPConfiguration(privateIPAddress string) *armnetwork.InterfaceIPConfiguration { 122 ipConfiguration := &armnetwork.InterfaceIPConfiguration{ 123 Properties: &armnetwork.InterfaceIPConfigurationPropertiesFormat{}, 124 } 125 if privateIPAddress != "" { 126 ipConfiguration.Properties.PrivateIPAddress = to.Ptr(privateIPAddress) 127 } 128 return ipConfiguration 129 } 130 131 func makePublicIPAddress(pipName, vmName, ipAddress string) *armnetwork.PublicIPAddress { 132 tags := map[string]*string{"juju-machine-name": &vmName} 133 pip := &armnetwork.PublicIPAddress{ 134 Name: to.Ptr(pipName), 135 Tags: tags, 136 Properties: &armnetwork.PublicIPAddressPropertiesFormat{}, 137 } 138 if ipAddress != "" { 139 pip.Properties.IPAddress = to.Ptr(ipAddress) 140 } 141 return pip 142 } 143 144 func makeSecurityGroup(rules ...*armnetwork.SecurityRule) armnetwork.SecurityGroup { 145 return armnetwork.SecurityGroup{ 146 Name: to.Ptr("juju-internal-nsg"), 147 ID: to.Ptr(internalSecurityGroupPath), 148 Properties: &armnetwork.SecurityGroupPropertiesFormat{ 149 SecurityRules: rules, 150 }, 151 } 152 } 153 154 func makeSecurityRule(name, ipAddress, ports string) *armnetwork.SecurityRule { 155 return &armnetwork.SecurityRule{ 156 Name: to.Ptr(name), 157 Properties: &armnetwork.SecurityRulePropertiesFormat{ 158 Protocol: to.Ptr(armnetwork.SecurityRuleProtocolTCP), 159 DestinationAddressPrefix: to.Ptr(ipAddress), 160 DestinationPortRange: to.Ptr(ports), 161 Access: to.Ptr(armnetwork.SecurityRuleAccessAllow), 162 Priority: to.Ptr(int32(200)), 163 Direction: to.Ptr(armnetwork.SecurityRuleDirectionInbound), 164 }, 165 } 166 } 167 168 func (s *instanceSuite) getInstance(c *gc.C, instID instance.Id) instances.Instance { 169 instances := s.getInstances(c, instID) 170 c.Assert(instances, gc.HasLen, 1) 171 return instances[0] 172 } 173 174 func (s *instanceSuite) getInstances(c *gc.C, ids ...instance.Id) []instances.Instance { 175 s.sender = s.getInstancesSender() 176 instances, err := s.env.Instances(s.callCtx, ids) 177 c.Assert(err, jc.ErrorIsNil) 178 s.sender = azuretesting.Senders{} 179 s.requests = nil 180 return instances 181 } 182 183 func (s *instanceSuite) getInstancesSender() azuretesting.Senders { 184 deploymentsSender := azuretesting.NewSenderWithValue(&armresources.DeploymentListResult{ 185 Value: s.deployments, 186 }) 187 deploymentsSender.PathPattern = ".*/deployments" 188 vmSender := azuretesting.NewSenderWithValue(&armcompute.VirtualMachineListResult{ 189 Value: s.vms, 190 }) 191 vmSender.PathPattern = ".*/virtualMachines" 192 nicsSender := azuretesting.NewSenderWithValue(&armnetwork.InterfaceListResult{ 193 Value: s.networkInterfaces, 194 }) 195 nicsSender.PathPattern = ".*/networkInterfaces" 196 pipsSender := azuretesting.NewSenderWithValue(&armnetwork.PublicIPAddressListResult{ 197 Value: s.publicIPAddresses, 198 }) 199 pipsSender.PathPattern = ".*/publicIPAddresses" 200 return azuretesting.Senders{deploymentsSender, vmSender, nicsSender, pipsSender} 201 } 202 203 func networkSecurityGroupSender(rules []*armnetwork.SecurityRule) *azuretesting.MockSender { 204 nsgSender := azuretesting.NewSenderWithValue(&armnetwork.SecurityGroup{ 205 Properties: &armnetwork.SecurityGroupPropertiesFormat{ 206 SecurityRules: rules, 207 }, 208 }) 209 nsgSender.PathPattern = ".*/networkSecurityGroups/juju-internal-nsg" 210 return nsgSender 211 } 212 213 func (s *instanceSuite) TestInstanceStatus(c *gc.C) { 214 inst := s.getInstance(c, "machine-0") 215 assertInstanceStatus(c, inst.Status(s.callCtx), status.Running, "") 216 } 217 218 func (s *instanceSuite) TestInstanceStatusDeploying(c *gc.C) { 219 s.deployments[1].Properties.ProvisioningState = to.Ptr(armresources.ProvisioningStateCreating) 220 inst := s.getInstance(c, "machine-1") 221 assertInstanceStatus(c, inst.Status(s.callCtx), status.Provisioning, "") 222 } 223 224 func (s *instanceSuite) TestInstanceStatusDeploymentFailed(c *gc.C) { 225 s.deployments[1].Properties.ProvisioningState = to.Ptr(armresources.ProvisioningStateFailed) 226 s.deployments[1].Properties.Error = &armresources.ErrorResponse{ 227 Details: []*armresources.ErrorResponse{{ 228 Message: to.Ptr("boom"), 229 }}, 230 } 231 inst := s.getInstance(c, "machine-1") 232 assertInstanceStatus(c, inst.Status(s.callCtx), status.ProvisioningError, "boom") 233 } 234 235 func (s *instanceSuite) TestInstanceStatusDeploymentCanceled(c *gc.C) { 236 s.deployments[1].Properties.ProvisioningState = to.Ptr(armresources.ProvisioningStateCanceled) 237 inst := s.getInstance(c, "machine-1") 238 assertInstanceStatus(c, inst.Status(s.callCtx), status.ProvisioningError, "Canceled") 239 } 240 241 func (s *instanceSuite) TestInstanceStatusUnsetProvisioningState(c *gc.C) { 242 s.deployments[1].Properties.ProvisioningState = to.Ptr(armresources.ProvisioningStateNotSpecified) 243 inst := s.getInstance(c, "machine-1") 244 assertInstanceStatus(c, inst.Status(s.callCtx), status.Allocating, "") 245 } 246 247 func assertInstanceStatus(c *gc.C, actual instance.Status, status status.Status, message string) { 248 c.Assert(actual, jc.DeepEquals, instance.Status{ 249 Status: status, 250 Message: message, 251 }) 252 } 253 254 func (s *instanceSuite) TestInstanceAddressesEmpty(c *gc.C) { 255 addresses, err := s.getInstance(c, "machine-0").Addresses(s.callCtx) 256 c.Assert(err, jc.ErrorIsNil) 257 c.Assert(addresses, gc.HasLen, 0) 258 } 259 260 func (s *instanceSuite) TestInstanceAddresses(c *gc.C) { 261 nic0IPConfigurations := []*armnetwork.InterfaceIPConfiguration{ 262 makeIPConfiguration("10.0.0.4"), 263 makeIPConfiguration("10.0.0.5"), 264 } 265 nic1IPConfigurations := []*armnetwork.InterfaceIPConfiguration{ 266 makeIPConfiguration(""), 267 } 268 s.networkInterfaces = []*armnetwork.Interface{ 269 makeNetworkInterface("nic-0", "machine-0", nic0IPConfigurations...), 270 makeNetworkInterface("nic-1", "machine-0", nic1IPConfigurations...), 271 makeNetworkInterface("nic-2", "machine-0"), 272 // unrelated NIC 273 makeNetworkInterface("nic-3", "machine-1"), 274 } 275 s.publicIPAddresses = []*armnetwork.PublicIPAddress{ 276 makePublicIPAddress("pip-0", "machine-0", "1.2.3.4"), 277 makePublicIPAddress("pip-1", "machine-0", "1.2.3.5"), 278 // unrelated PIP 279 makePublicIPAddress("pip-2", "machine-1", "1.2.3.6"), 280 } 281 addresses, err := s.getInstance(c, "machine-0").Addresses(s.callCtx) 282 c.Assert(err, jc.ErrorIsNil) 283 c.Assert(addresses, jc.DeepEquals, corenetwork.NewMachineAddresses([]string{ 284 "10.0.0.4", "10.0.0.5", "1.2.3.4", "1.2.3.5", 285 }).AsProviderAddresses()) 286 } 287 288 func (s *instanceSuite) TestMultipleInstanceAddresses(c *gc.C) { 289 nic0IPConfiguration := makeIPConfiguration("10.0.0.4") 290 nic1IPConfiguration := makeIPConfiguration("10.0.0.5") 291 s.networkInterfaces = []*armnetwork.Interface{ 292 makeNetworkInterface("nic-0", "machine-0", nic0IPConfiguration), 293 makeNetworkInterface("nic-1", "machine-1", nic1IPConfiguration), 294 } 295 s.publicIPAddresses = []*armnetwork.PublicIPAddress{ 296 makePublicIPAddress("pip-0", "machine-0", "1.2.3.4"), 297 makePublicIPAddress("pip-1", "machine-1", "1.2.3.5"), 298 } 299 instances := s.getInstances(c, "machine-0", "machine-1") 300 c.Assert(instances, gc.HasLen, 2) 301 302 inst0Addresses, err := instances[0].Addresses(s.callCtx) 303 c.Assert(err, jc.ErrorIsNil) 304 c.Assert(inst0Addresses, jc.DeepEquals, corenetwork.NewMachineAddresses([]string{ 305 "10.0.0.4", "1.2.3.4", 306 }).AsProviderAddresses()) 307 308 inst1Addresses, err := instances[1].Addresses(s.callCtx) 309 c.Assert(err, jc.ErrorIsNil) 310 c.Assert(inst1Addresses, jc.DeepEquals, corenetwork.NewMachineAddresses([]string{ 311 "10.0.0.5", "1.2.3.5", 312 }).AsProviderAddresses()) 313 } 314 315 func (s *instanceSuite) TestIngressRulesEmpty(c *gc.C) { 316 inst := s.getInstance(c, "machine-0") 317 fwInst, ok := inst.(instances.InstanceFirewaller) 318 c.Assert(ok, gc.Equals, true) 319 nsgSender := networkSecurityGroupSender(nil) 320 s.sender = azuretesting.Senders{nsgSender} 321 rules, err := fwInst.IngressRules(s.callCtx, "0") 322 c.Assert(err, jc.ErrorIsNil) 323 c.Assert(rules, gc.HasLen, 0) 324 } 325 326 func (s *instanceSuite) setupSecurityGroupRules(nsgRules ...*armnetwork.SecurityRule) *azuretesting.Senders { 327 nsg := &armnetwork.SecurityGroup{ 328 ID: &internalSecurityGroupPath, 329 Name: to.Ptr("juju-internal-nsg"), 330 Properties: &armnetwork.SecurityGroupPropertiesFormat{ 331 SecurityRules: nsgRules, 332 }, 333 } 334 nic0IPConfigurations := []*armnetwork.InterfaceIPConfiguration{ 335 makeIPConfiguration("10.0.0.4"), 336 } 337 nic0IPConfigurations[0].Properties.Primary = to.Ptr(true) 338 nic0IPConfigurations[0].Properties.Subnet = &armnetwork.Subnet{ 339 ID: &internalSubnetPath, 340 Properties: &armnetwork.SubnetPropertiesFormat{ 341 NetworkSecurityGroup: nsg, 342 }, 343 } 344 s.networkInterfaces = []*armnetwork.Interface{ 345 makeNetworkInterface("nic-0", "machine-0", nic0IPConfigurations...), 346 makeNetworkInterface("nic-2", "machine-0"), 347 // unrelated NIC 348 makeNetworkInterface("nic-3", "machine-1"), 349 } 350 return &azuretesting.Senders{ 351 makeSender(internalSubnetPath, nic0IPConfigurations[0].Properties.Subnet), // GET: subnets to get security group 352 networkSecurityGroupSender(nsgRules), 353 } 354 } 355 356 func (s *instanceSuite) TestIngressRules(c *gc.C) { 357 nsgRules := []*armnetwork.SecurityRule{{ 358 Name: to.Ptr("machine-0-xyzzy"), 359 Properties: &armnetwork.SecurityRulePropertiesFormat{ 360 Protocol: to.Ptr(armnetwork.SecurityRuleProtocolUDP), 361 DestinationPortRange: to.Ptr("*"), 362 Access: to.Ptr(armnetwork.SecurityRuleAccessAllow), 363 Priority: to.Ptr(int32(200)), 364 Direction: to.Ptr(armnetwork.SecurityRuleDirectionInbound), 365 }, 366 }, { 367 Name: to.Ptr("machine-0-tcpcp-1"), 368 Properties: &armnetwork.SecurityRulePropertiesFormat{ 369 Protocol: to.Ptr(armnetwork.SecurityRuleProtocolTCP), 370 DestinationPortRange: to.Ptr("1000-2000"), 371 SourceAddressPrefix: to.Ptr("*"), 372 Access: to.Ptr(armnetwork.SecurityRuleAccessAllow), 373 Priority: to.Ptr(int32(201)), 374 Direction: to.Ptr(armnetwork.SecurityRuleDirectionInbound), 375 }, 376 }, { 377 Name: to.Ptr("machine-0-tcpcp-2"), 378 Properties: &armnetwork.SecurityRulePropertiesFormat{ 379 Protocol: to.Ptr(armnetwork.SecurityRuleProtocolTCP), 380 DestinationPortRange: to.Ptr("1000-2000"), 381 SourceAddressPrefix: to.Ptr("192.168.1.0/24"), 382 Access: to.Ptr(armnetwork.SecurityRuleAccessAllow), 383 Priority: to.Ptr(int32(201)), 384 Direction: to.Ptr(armnetwork.SecurityRuleDirectionInbound), 385 }, 386 }, { 387 Name: to.Ptr("machine-0-tcpcp-3"), 388 Properties: &armnetwork.SecurityRulePropertiesFormat{ 389 Protocol: to.Ptr(armnetwork.SecurityRuleProtocolTCP), 390 DestinationPortRange: to.Ptr("1000-2000"), 391 SourceAddressPrefix: to.Ptr("10.0.0.0/24"), 392 Access: to.Ptr(armnetwork.SecurityRuleAccessAllow), 393 Priority: to.Ptr(int32(201)), 394 Direction: to.Ptr(armnetwork.SecurityRuleDirectionInbound), 395 }, 396 }, { 397 Name: to.Ptr("machine-0-http"), 398 Properties: &armnetwork.SecurityRulePropertiesFormat{ 399 Protocol: to.Ptr(armnetwork.SecurityRuleProtocolAsterisk), 400 DestinationPortRange: to.Ptr("80"), 401 Access: to.Ptr(armnetwork.SecurityRuleAccessAllow), 402 Priority: to.Ptr(int32(202)), 403 Direction: to.Ptr(armnetwork.SecurityRuleDirectionInbound), 404 }, 405 }, { 406 Name: to.Ptr("machine-00-ignored"), 407 Properties: &armnetwork.SecurityRulePropertiesFormat{ 408 Protocol: to.Ptr(armnetwork.SecurityRuleProtocolTCP), 409 DestinationPortRange: to.Ptr("80"), 410 Access: to.Ptr(armnetwork.SecurityRuleAccessAllow), 411 Priority: to.Ptr(int32(202)), 412 Direction: to.Ptr(armnetwork.SecurityRuleDirectionInbound), 413 }, 414 }, { 415 Name: to.Ptr("machine-0-ignored"), 416 Properties: &armnetwork.SecurityRulePropertiesFormat{ 417 Protocol: to.Ptr(armnetwork.SecurityRuleProtocolTCP), 418 DestinationPortRange: to.Ptr("80"), 419 Access: to.Ptr(armnetwork.SecurityRuleAccessDeny), 420 Priority: to.Ptr(int32(202)), 421 Direction: to.Ptr(armnetwork.SecurityRuleDirectionInbound), 422 }, 423 }, { 424 Name: to.Ptr("machine-0-ignored"), 425 Properties: &armnetwork.SecurityRulePropertiesFormat{ 426 Protocol: to.Ptr(armnetwork.SecurityRuleProtocolTCP), 427 DestinationPortRange: to.Ptr("80"), 428 Access: to.Ptr(armnetwork.SecurityRuleAccessAllow), 429 Priority: to.Ptr(int32(202)), 430 Direction: to.Ptr(armnetwork.SecurityRuleDirectionOutbound), 431 }, 432 }, { 433 Name: to.Ptr("machine-0-ignored"), 434 Properties: &armnetwork.SecurityRulePropertiesFormat{ 435 Protocol: to.Ptr(armnetwork.SecurityRuleProtocolTCP), 436 DestinationPortRange: to.Ptr("80"), 437 Access: to.Ptr(armnetwork.SecurityRuleAccessAllow), 438 Priority: to.Ptr(int32(199)), // internal range 439 Direction: to.Ptr(armnetwork.SecurityRuleDirectionInbound), 440 }, 441 }} 442 nsgSender := s.setupSecurityGroupRules(nsgRules...) 443 inst := s.getInstance(c, "machine-0") 444 s.sender = *nsgSender 445 446 fwInst, ok := inst.(instances.InstanceFirewaller) 447 c.Assert(ok, gc.Equals, true) 448 449 rules, err := fwInst.IngressRules(s.callCtx, "0") 450 c.Assert(err, jc.ErrorIsNil) 451 c.Assert(rules, jc.DeepEquals, firewall.IngressRules{ 452 firewall.NewIngressRule(corenetwork.MustParsePortRange("80/tcp"), firewall.AllNetworksIPV4CIDR), 453 firewall.NewIngressRule(corenetwork.MustParsePortRange("1000-2000/tcp"), firewall.AllNetworksIPV4CIDR, "192.168.1.0/24", "10.0.0.0/24"), 454 firewall.NewIngressRule(corenetwork.MustParsePortRange("1-65535/udp"), firewall.AllNetworksIPV4CIDR), 455 firewall.NewIngressRule(corenetwork.MustParsePortRange("80/udp"), firewall.AllNetworksIPV4CIDR), 456 }) 457 } 458 459 func (s *instanceSuite) TestInstanceClosePorts(c *gc.C) { 460 nsgSender := s.setupSecurityGroupRules() 461 inst := s.getInstance(c, "machine-0") 462 fwInst, ok := inst.(instances.InstanceFirewaller) 463 c.Assert(ok, gc.Equals, true) 464 465 sender := &azuretesting.MockSender{} 466 notFoundSender := &azuretesting.MockSender{} 467 notFoundSender.AppendAndRepeatResponse(azuretesting.NewResponseWithStatus( 468 "rule not found", http.StatusNotFound, 469 ), 2) 470 s.sender = azuretesting.Senders{nsgSender, sender, notFoundSender, notFoundSender, notFoundSender} 471 472 err := fwInst.ClosePorts(s.callCtx, "0", firewall.IngressRules{ 473 firewall.NewIngressRule(corenetwork.MustParsePortRange("1000/tcp")), 474 firewall.NewIngressRule(corenetwork.MustParsePortRange("1000-2000/udp")), 475 firewall.NewIngressRule(corenetwork.MustParsePortRange("1000-2000/udp"), "192.168.1.0/24", "10.0.0.0/24"), 476 }) 477 c.Assert(err, jc.ErrorIsNil) 478 479 c.Assert(s.requests, gc.HasLen, 5) 480 c.Assert(s.requests[0].Method, gc.Equals, "GET") 481 c.Assert(s.requests[0].URL.Path, gc.Equals, internalSubnetPath) 482 c.Assert(s.requests[1].Method, gc.Equals, "DELETE") 483 c.Assert(s.requests[1].URL.Path, gc.Equals, securityRulePath("machine-0-tcp-1000")) 484 c.Assert(s.requests[2].Method, gc.Equals, "DELETE") 485 c.Assert(s.requests[2].URL.Path, gc.Equals, securityRulePath("machine-0-udp-1000-2000")) 486 c.Assert(s.requests[3].Method, gc.Equals, "DELETE") 487 c.Assert(s.requests[3].URL.Path, gc.Equals, securityRulePath("machine-0-udp-1000-2000-cidr-10-0-0-0-24")) 488 c.Assert(s.requests[4].Method, gc.Equals, "DELETE") 489 c.Assert(s.requests[4].URL.Path, gc.Equals, securityRulePath("machine-0-udp-1000-2000-cidr-192-168-1-0-24")) 490 } 491 492 func (s *instanceSuite) TestInstanceOpenPorts(c *gc.C) { 493 nsgSender := s.setupSecurityGroupRules() 494 inst := s.getInstance(c, "machine-0") 495 fwInst, ok := inst.(instances.InstanceFirewaller) 496 c.Assert(ok, gc.Equals, true) 497 498 okSender := &azuretesting.MockSender{} 499 okSender.AppendResponse(azuretesting.NewResponseWithContent("{}")) 500 s.sender = azuretesting.Senders{nsgSender, okSender, okSender, okSender, okSender} 501 502 err := fwInst.OpenPorts(s.callCtx, "0", firewall.IngressRules{ 503 firewall.NewIngressRule(corenetwork.MustParsePortRange("1000/tcp")), 504 firewall.NewIngressRule(corenetwork.MustParsePortRange("1000-2000/udp")), 505 firewall.NewIngressRule(corenetwork.MustParsePortRange("1000-2000/tcp"), "192.168.1.0/24", "10.0.0.0/24"), 506 }) 507 c.Assert(err, jc.ErrorIsNil) 508 509 c.Assert(s.requests, gc.HasLen, 5) 510 c.Assert(s.requests[0].Method, gc.Equals, "GET") 511 c.Assert(s.requests[0].URL.Path, gc.Equals, internalSubnetPath) 512 c.Assert(s.requests[1].Method, gc.Equals, "PUT") 513 c.Assert(s.requests[1].URL.Path, gc.Equals, securityRulePath("machine-0-tcp-1000")) 514 assertRequestBody(c, s.requests[1], &armnetwork.SecurityRule{ 515 Properties: &armnetwork.SecurityRulePropertiesFormat{ 516 Description: to.Ptr("1000/tcp from *"), 517 Protocol: to.Ptr(armnetwork.SecurityRuleProtocolTCP), 518 SourcePortRange: to.Ptr("*"), 519 SourceAddressPrefix: to.Ptr("*"), 520 DestinationPortRange: to.Ptr("1000"), 521 DestinationAddressPrefix: to.Ptr("10.0.0.4"), 522 Access: to.Ptr(armnetwork.SecurityRuleAccessAllow), 523 Priority: to.Ptr(int32(200)), 524 Direction: to.Ptr(armnetwork.SecurityRuleDirectionInbound), 525 }, 526 }) 527 c.Assert(s.requests[2].Method, gc.Equals, "PUT") 528 c.Assert(s.requests[2].URL.Path, gc.Equals, securityRulePath("machine-0-udp-1000-2000")) 529 assertRequestBody(c, s.requests[2], &armnetwork.SecurityRule{ 530 Properties: &armnetwork.SecurityRulePropertiesFormat{ 531 Description: to.Ptr("1000-2000/udp from *"), 532 Protocol: to.Ptr(armnetwork.SecurityRuleProtocolUDP), 533 SourcePortRange: to.Ptr("*"), 534 SourceAddressPrefix: to.Ptr("*"), 535 DestinationPortRange: to.Ptr("1000-2000"), 536 DestinationAddressPrefix: to.Ptr("10.0.0.4"), 537 Access: to.Ptr(armnetwork.SecurityRuleAccessAllow), 538 Priority: to.Ptr(int32(201)), 539 Direction: to.Ptr(armnetwork.SecurityRuleDirectionInbound), 540 }, 541 }) 542 c.Assert(s.requests[3].Method, gc.Equals, "PUT") 543 c.Assert(s.requests[3].URL.Path, gc.Equals, securityRulePath("machine-0-tcp-1000-2000-cidr-10-0-0-0-24")) 544 assertRequestBody(c, s.requests[3], &armnetwork.SecurityRule{ 545 Properties: &armnetwork.SecurityRulePropertiesFormat{ 546 Description: to.Ptr("1000-2000/tcp from 10.0.0.0/24"), 547 Protocol: to.Ptr(armnetwork.SecurityRuleProtocolTCP), 548 SourcePortRange: to.Ptr("*"), 549 SourceAddressPrefix: to.Ptr("10.0.0.0/24"), 550 DestinationPortRange: to.Ptr("1000-2000"), 551 DestinationAddressPrefix: to.Ptr("10.0.0.4"), 552 Access: to.Ptr(armnetwork.SecurityRuleAccessAllow), 553 Priority: to.Ptr(int32(202)), 554 Direction: to.Ptr(armnetwork.SecurityRuleDirectionInbound), 555 }, 556 }) 557 c.Assert(s.requests[4].Method, gc.Equals, "PUT") 558 c.Assert(s.requests[4].URL.Path, gc.Equals, securityRulePath("machine-0-tcp-1000-2000-cidr-192-168-1-0-24")) 559 assertRequestBody(c, s.requests[4], &armnetwork.SecurityRule{ 560 Properties: &armnetwork.SecurityRulePropertiesFormat{ 561 Description: to.Ptr("1000-2000/tcp from 192.168.1.0/24"), 562 Protocol: to.Ptr(armnetwork.SecurityRuleProtocolTCP), 563 SourcePortRange: to.Ptr("*"), 564 SourceAddressPrefix: to.Ptr("192.168.1.0/24"), 565 DestinationPortRange: to.Ptr("1000-2000"), 566 DestinationAddressPrefix: to.Ptr("10.0.0.4"), 567 Access: to.Ptr(armnetwork.SecurityRuleAccessAllow), 568 Priority: to.Ptr(int32(203)), 569 Direction: to.Ptr(armnetwork.SecurityRuleDirectionInbound), 570 }, 571 }) 572 } 573 574 func (s *instanceSuite) TestInstanceOpenPortsAlreadyOpen(c *gc.C) { 575 nsgRule := &armnetwork.SecurityRule{ 576 Name: to.Ptr("machine-0-tcp-1000"), 577 Properties: &armnetwork.SecurityRulePropertiesFormat{ 578 Protocol: to.Ptr(armnetwork.SecurityRuleProtocolAsterisk), 579 DestinationPortRange: to.Ptr("1000"), 580 Access: to.Ptr(armnetwork.SecurityRuleAccessAllow), 581 Priority: to.Ptr(int32(202)), 582 Direction: to.Ptr(armnetwork.SecurityRuleDirectionInbound), 583 }, 584 } 585 nsgSender := s.setupSecurityGroupRules(nsgRule) 586 inst := s.getInstance(c, "machine-0") 587 fwInst, ok := inst.(instances.InstanceFirewaller) 588 c.Assert(ok, gc.Equals, true) 589 590 okSender := &azuretesting.MockSender{} 591 okSender.AppendResponse(azuretesting.NewResponseWithContent("{}")) 592 s.sender = azuretesting.Senders{nsgSender, okSender, okSender} 593 594 err := fwInst.OpenPorts(s.callCtx, "0", firewall.IngressRules{ 595 firewall.NewIngressRule(corenetwork.MustParsePortRange("1000/tcp")), 596 firewall.NewIngressRule(corenetwork.MustParsePortRange("1000-2000/udp")), 597 }) 598 c.Assert(err, jc.ErrorIsNil) 599 600 c.Assert(s.requests, gc.HasLen, 2) 601 c.Assert(s.requests[0].Method, gc.Equals, "GET") 602 c.Assert(s.requests[0].URL.Path, gc.Equals, internalSubnetPath) 603 c.Assert(s.requests[1].Method, gc.Equals, "PUT") 604 c.Assert(s.requests[1].URL.Path, gc.Equals, securityRulePath("machine-0-udp-1000-2000")) 605 assertRequestBody(c, s.requests[1], &armnetwork.SecurityRule{ 606 Properties: &armnetwork.SecurityRulePropertiesFormat{ 607 Description: to.Ptr("1000-2000/udp from *"), 608 Protocol: to.Ptr(armnetwork.SecurityRuleProtocolUDP), 609 SourcePortRange: to.Ptr("*"), 610 SourceAddressPrefix: to.Ptr("*"), 611 DestinationPortRange: to.Ptr("1000-2000"), 612 DestinationAddressPrefix: to.Ptr("10.0.0.4"), 613 Access: to.Ptr(armnetwork.SecurityRuleAccessAllow), 614 Priority: to.Ptr(int32(200)), 615 Direction: to.Ptr(armnetwork.SecurityRuleDirectionInbound), 616 }, 617 }) 618 } 619 620 func (s *instanceSuite) TestInstanceOpenPortsNoInternalAddress(c *gc.C) { 621 s.networkInterfaces = []*armnetwork.Interface{ 622 makeNetworkInterface("nic-0", "machine-0"), 623 } 624 inst := s.getInstance(c, "machine-0") 625 fwInst, ok := inst.(instances.InstanceFirewaller) 626 c.Assert(ok, gc.Equals, true) 627 err := fwInst.OpenPorts(s.callCtx, "0", nil) 628 c.Assert(err, jc.ErrorIsNil) 629 c.Assert(s.requests, gc.HasLen, 0) 630 } 631 632 func (s *instanceSuite) TestAllInstances(c *gc.C) { 633 s.sender = s.getInstancesSender() 634 instances, err := s.env.AllInstances(s.callCtx) 635 c.Assert(err, jc.ErrorIsNil) 636 c.Assert(instances, gc.HasLen, 2) 637 c.Assert(instances[0].Id(), gc.Equals, instance.Id("machine-0")) 638 c.Assert(instances[1].Id(), gc.Equals, instance.Id("machine-1")) 639 } 640 641 func (s *instanceSuite) TestAllRunningInstances(c *gc.C) { 642 s.sender = s.getInstancesSender() 643 instances, err := s.env.AllRunningInstances(s.callCtx) 644 c.Assert(err, jc.ErrorIsNil) 645 c.Assert(instances, gc.HasLen, 2) 646 c.Assert(instances[0].Id(), gc.Equals, instance.Id("machine-0")) 647 c.Assert(instances[1].Id(), gc.Equals, instance.Id("machine-1")) 648 } 649 650 func (s *instanceSuite) TestControllerInstancesSomePending(c *gc.C) { 651 *((s.deployments[1].Properties.Dependencies)[0].DependsOn)[0].ResourceName = "juju-controller" 652 s.sender = s.getInstancesSender() 653 ids, err := s.env.ControllerInstances(s.callCtx, testing.ControllerTag.Id()) 654 c.Assert(err, jc.ErrorIsNil) 655 c.Assert(ids, gc.HasLen, 2) 656 c.Assert(ids[0], gc.Equals, instance.Id("machine-0")) 657 c.Assert(ids[1], gc.Equals, instance.Id("machine-1")) 658 } 659 660 func (s *instanceSuite) TestControllerInstances(c *gc.C) { 661 s.sender = s.getInstancesSender() 662 ids, err := s.env.ControllerInstances(s.callCtx, testing.ControllerTag.Id()) 663 c.Assert(err, jc.ErrorIsNil) 664 c.Assert(ids, gc.HasLen, 1) 665 c.Assert(ids[0], gc.Equals, instance.Id("machine-0")) 666 } 667 668 var internalSecurityGroupPath = path.Join( 669 "/subscriptions", fakeManagedSubscriptionId, 670 "resourceGroups", "juju-testmodel-"+testing.ModelTag.Id()[:8], 671 "providers/Microsoft.Network/networkSecurityGroups/juju-internal-nsg", 672 ) 673 674 var internalSubnetPath = path.Join( 675 "/subscriptions", fakeManagedSubscriptionId, 676 "resourceGroups/juju-testmodel-model-deadbeef-0bad-400d-8000-4b1d0d06f00d", 677 "providers/Microsoft.Network/virtualNetworks/juju-internal-network/subnets/juju-internal-subnet", 678 ) 679 680 func securityRulePath(ruleName string) string { 681 return path.Join(internalSecurityGroupPath, "securityRules", ruleName) 682 }