Skip to content

Commit 6c161a7

Browse files
committed
Add checks on Public IPs for shared networks
1 parent 377784a commit 6c161a7

File tree

2 files changed

+91
-0
lines changed

2 files changed

+91
-0
lines changed

pkg/cloud/instance.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,35 @@ func (c *client) CheckDomainLimits(fd *infrav1.CloudStackFailureDomain, offering
257257
return nil
258258
}
259259

260+
// CheckNetworkLimits Checks the available IPs for a shared network
261+
func (c *client) CheckNetworkLimits(fd *infrav1.CloudStackFailureDomain) error {
262+
if fd.Spec.Zone.Network.Type == NetworkTypeShared {
263+
264+
p := c.cs.Address.NewListPublicIpAddressesParams()
265+
p.SetAllocatedonly(false)
266+
p.SetNetworkid(fd.Spec.Zone.Network.ID)
267+
p.SetZoneid(fd.Spec.Zone.ID)
268+
p.SetListall(true)
269+
p.SetForvirtualnetwork(false)
270+
publicAddresses, err := c.cs.Address.ListPublicIpAddresses(p)
271+
if err != nil {
272+
return err
273+
}
274+
275+
// freeAddressCount = publicAddresses.PublicIpAddresses
276+
freeIPCount := 0
277+
for _, publicIP := range publicAddresses.PublicIpAddresses {
278+
if publicIP.State == "Free" {
279+
freeIPCount++
280+
}
281+
}
282+
if freeIPCount < 1 {
283+
return fmt.Errorf("no public IPs available in the shared network id: %s name: %s", fd.Spec.Zone.ID, fd.Spec.Zone.Name)
284+
}
285+
}
286+
return nil
287+
}
288+
260289
// CheckLimitsAndCreateVM will check the account & domain limits and then create a
261290
// VM instance, and sets the infrastructure machine spec and status accordingly.
262291
func (c *client) CheckLimitsAndCreateVM(
@@ -364,6 +393,10 @@ func (c *client) GetOrCreateVMInstance(
364393
return err
365394
}
366395

396+
if err := c.CheckNetworkLimits(fd); err != nil {
397+
return err
398+
}
399+
367400
// Create VM instance.
368401
if err := c.CheckLimitsAndCreateVM(csMachine, capiMachine, csCluster, fd, affinity, userData); err != nil {
369402
return err

pkg/cloud/instance_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ var _ = Describe("Instance", func() {
4848
var (
4949
mockCtrl *gomock.Controller
5050
mockClient *cloudstack.CloudStackClient
51+
as *cloudstack.MockAddressServiceIface
5152
vms *cloudstack.MockVirtualMachineServiceIface
5253
sos *cloudstack.MockServiceOfferingServiceIface
5354
dos *cloudstack.MockDiskOfferingServiceIface
@@ -64,6 +65,7 @@ var _ = Describe("Instance", func() {
6465
dos = mockClient.DiskOffering.(*cloudstack.MockDiskOfferingServiceIface)
6566
ts = mockClient.Template.(*cloudstack.MockTemplateServiceIface)
6667
vs = mockClient.Volume.(*cloudstack.MockVolumeServiceIface)
68+
as = mockClient.Address.(*cloudstack.MockAddressServiceIface)
6769
client = cloud.NewClientFromCSAPIClient(mockClient)
6870

6971
dummies.SetDummyVars()
@@ -126,6 +128,11 @@ var _ = Describe("Instance", func() {
126128
expectVMNotFound := func() {
127129
vms.EXPECT().GetVirtualMachinesMetricByID(*dummies.CSMachine1.Spec.InstanceID).Return(nil, -1, notFoundError)
128130
vms.EXPECT().GetVirtualMachinesMetricByName(dummies.CSMachine1.Name).Return(nil, -1, notFoundError)
131+
aslp := &cloudstack.ListPublicIpAddressesParams{}
132+
as.EXPECT().NewListPublicIpAddressesParams().Return(aslp)
133+
as.EXPECT().ListPublicIpAddresses(aslp).Return(&cloudstack.ListPublicIpAddressesResponse{
134+
Count: 2, PublicIpAddresses: []*cloudstack.PublicIpAddress{{State: "Allocated"}, {State: "Free"}},
135+
}, nil)
129136
}
130137

131138
It("doesn't re-create if one already exists.", func() {
@@ -324,6 +331,11 @@ var _ = Describe("Instance", func() {
324331
dummies.CSMachine1.Spec.Offering.Name = "offering"
325332
dummies.CSMachine1.Spec.Template.Name = "template"
326333

334+
aslp := &cloudstack.ListPublicIpAddressesParams{}
335+
as.EXPECT().NewListPublicIpAddressesParams().Return(aslp)
336+
as.EXPECT().ListPublicIpAddresses(aslp).Return(&cloudstack.ListPublicIpAddressesResponse{
337+
Count: 2, PublicIpAddresses: []*cloudstack.PublicIpAddress{{State: "Allocated"}, {State: "Free"}},
338+
}, nil)
327339
sos.EXPECT().GetServiceOfferingByName(dummies.CSMachine1.Spec.Offering.Name, gomock.Any()).Return(&cloudstack.ServiceOffering{
328340
Id: offeringFakeID,
329341
Cpunumber: 1,
@@ -344,6 +356,11 @@ var _ = Describe("Instance", func() {
344356
dummies.CSMachine1.Spec.Template.Name = "template"
345357
dummies.CSMachine1.Spec.DiskOffering = infrav1.CloudStackResourceDiskOffering{}
346358

359+
aslp := &cloudstack.ListPublicIpAddressesParams{}
360+
as.EXPECT().NewListPublicIpAddressesParams().Return(aslp)
361+
as.EXPECT().ListPublicIpAddresses(aslp).Return(&cloudstack.ListPublicIpAddressesResponse{
362+
Count: 2, PublicIpAddresses: []*cloudstack.PublicIpAddress{{State: "Allocated"}, {State: "Free"}},
363+
}, nil)
347364
sos.EXPECT().GetServiceOfferingByName(dummies.CSMachine1.Spec.Offering.Name, gomock.Any()).Return(&cloudstack.ServiceOffering{
348365
Id: offeringFakeID,
349366
Cpunumber: 1,
@@ -362,6 +379,11 @@ var _ = Describe("Instance", func() {
362379
dummies.CSMachine1.Spec.Offering.Name = ""
363380
dummies.CSMachine1.Spec.Template.Name = "template"
364381

382+
aslp := &cloudstack.ListPublicIpAddressesParams{}
383+
as.EXPECT().NewListPublicIpAddressesParams().Return(aslp)
384+
as.EXPECT().ListPublicIpAddresses(aslp).Return(&cloudstack.ListPublicIpAddressesResponse{
385+
Count: 2, PublicIpAddresses: []*cloudstack.PublicIpAddress{{State: "Allocated"}, {State: "Free"}},
386+
}, nil)
365387
sos.EXPECT().GetServiceOfferingByID(dummies.CSMachine1.Spec.Offering.ID).Return(&cloudstack.ServiceOffering{
366388
Id: offeringFakeID,
367389
Cpunumber: 1,
@@ -387,6 +409,11 @@ var _ = Describe("Instance", func() {
387409
Cpunumber: 1,
388410
Memory: 1024,
389411
}, 1, nil)
412+
aslp := &cloudstack.ListPublicIpAddressesParams{}
413+
as.EXPECT().NewListPublicIpAddressesParams().Return(aslp)
414+
as.EXPECT().ListPublicIpAddresses(aslp).Return(&cloudstack.ListPublicIpAddressesResponse{
415+
Count: 2, PublicIpAddresses: []*cloudstack.PublicIpAddress{{State: "Allocated"}, {State: "Free"}},
416+
}, nil)
390417
ts.EXPECT().GetTemplateByID(dummies.CSMachine1.Spec.Template.ID, executableFilter).Return(&cloudstack.Template{Name: ""}, 1, nil)
391418
dos.EXPECT().GetDiskOfferingID(dummies.CSMachine1.Spec.DiskOffering.Name, gomock.Any()).Return(diskOfferingFakeID, 1, nil)
392419
dos.EXPECT().GetDiskOfferingByID(dummies.CSMachine1.Spec.DiskOffering.ID).Return(&cloudstack.DiskOffering{Iscustomized: false}, 1, nil)
@@ -401,6 +428,11 @@ var _ = Describe("Instance", func() {
401428
dummies.CSMachine1.Spec.Offering.Name = ""
402429
dummies.CSMachine1.Spec.Template.Name = ""
403430

431+
aslp := &cloudstack.ListPublicIpAddressesParams{}
432+
as.EXPECT().NewListPublicIpAddressesParams().Return(aslp)
433+
as.EXPECT().ListPublicIpAddresses(aslp).Return(&cloudstack.ListPublicIpAddressesResponse{
434+
Count: 2, PublicIpAddresses: []*cloudstack.PublicIpAddress{{State: "Allocated"}, {State: "Free"}},
435+
}, nil)
404436
sos.EXPECT().GetServiceOfferingByID(dummies.CSMachine1.Spec.Offering.ID).
405437
Return(&cloudstack.ServiceOffering{
406438
Id: offeringFakeID,
@@ -424,6 +456,11 @@ var _ = Describe("Instance", func() {
424456
dummies.CSMachine1.Spec.Offering.Name = "offering"
425457
dummies.CSMachine1.Spec.Template.Name = "template"
426458

459+
aslp := &cloudstack.ListPublicIpAddressesParams{}
460+
as.EXPECT().NewListPublicIpAddressesParams().Return(aslp)
461+
as.EXPECT().ListPublicIpAddresses(aslp).Return(&cloudstack.ListPublicIpAddressesResponse{
462+
Count: 2, PublicIpAddresses: []*cloudstack.PublicIpAddress{{State: "Allocated"}, {State: "Free"}},
463+
}, nil)
427464
sos.EXPECT().GetServiceOfferingByID(dummies.CSMachine1.Spec.Offering.ID).Return(&cloudstack.ServiceOffering{
428465
Id: dummies.CSMachine1.Spec.Offering.ID,
429466
Name: dummies.CSMachine1.Spec.Offering.Name,
@@ -451,6 +488,11 @@ var _ = Describe("Instance", func() {
451488
dummies.CSMachine1.Spec.Offering.Name = "offering"
452489
dummies.CSMachine1.Spec.Template.Name = "template"
453490

491+
aslp := &cloudstack.ListPublicIpAddressesParams{}
492+
as.EXPECT().NewListPublicIpAddressesParams().Return(aslp)
493+
as.EXPECT().ListPublicIpAddresses(aslp).Return(&cloudstack.ListPublicIpAddressesResponse{
494+
Count: 2, PublicIpAddresses: []*cloudstack.PublicIpAddress{{State: "Allocated"}, {State: "Free"}},
495+
}, nil)
454496
sos.EXPECT().GetServiceOfferingByID(dummies.CSMachine1.Spec.Offering.ID).Return(&cloudstack.ServiceOffering{Name: "offering-not-match"}, 1, nil)
455497
requiredRegexp := "offering name %s does not match name %s returned using UUID %s"
456498
Ω(client.GetOrCreateVMInstance(
@@ -464,6 +506,11 @@ var _ = Describe("Instance", func() {
464506
dummies.CSMachine1.Spec.Offering.Name = "offering"
465507
dummies.CSMachine1.Spec.Template.Name = "template"
466508

509+
aslp := &cloudstack.ListPublicIpAddressesParams{}
510+
as.EXPECT().NewListPublicIpAddressesParams().Return(aslp)
511+
as.EXPECT().ListPublicIpAddresses(aslp).Return(&cloudstack.ListPublicIpAddressesResponse{
512+
Count: 2, PublicIpAddresses: []*cloudstack.PublicIpAddress{{State: "Allocated"}, {State: "Free"}},
513+
}, nil)
467514
sos.EXPECT().GetServiceOfferingByID(dummies.CSMachine1.Spec.Offering.ID).Return(&cloudstack.ServiceOffering{Name: "offering"}, 1, nil)
468515
ts.EXPECT().GetTemplateByID(dummies.CSMachine1.Spec.Template.ID, executableFilter).Return(&cloudstack.Template{Name: "template-not-match"}, 1, nil)
469516
requiredRegexp := "template name %s does not match name %s returned using UUID %s"
@@ -481,6 +528,11 @@ var _ = Describe("Instance", func() {
481528
dummies.CSMachine1.Spec.Template.Name = "template"
482529
dummies.CSMachine1.Spec.DiskOffering.Name = "diskoffering"
483530

531+
aslp := &cloudstack.ListPublicIpAddressesParams{}
532+
as.EXPECT().NewListPublicIpAddressesParams().Return(aslp)
533+
as.EXPECT().ListPublicIpAddresses(aslp).Return(&cloudstack.ListPublicIpAddressesResponse{
534+
Count: 2, PublicIpAddresses: []*cloudstack.PublicIpAddress{{State: "Allocated"}, {State: "Free"}},
535+
}, nil)
484536
sos.EXPECT().GetServiceOfferingByID(dummies.CSMachine1.Spec.Offering.ID).Return(&cloudstack.ServiceOffering{Name: "offering"}, 1, nil)
485537
ts.EXPECT().GetTemplateByID(dummies.CSMachine1.Spec.Template.ID, executableFilter).Return(&cloudstack.Template{Name: "template"}, 1, nil)
486538
dos.EXPECT().GetDiskOfferingID(dummies.CSMachine1.Spec.DiskOffering.Name, gomock.Any()).Return(diskOfferingFakeID+"-not-match", 1, nil)
@@ -509,6 +561,12 @@ var _ = Describe("Instance", func() {
509561
vms.EXPECT().
510562
GetVirtualMachinesMetricByName(dummies.CSMachine1.Name).
511563
Return(nil, -1, notFoundError)
564+
565+
aslp := &cloudstack.ListPublicIpAddressesParams{}
566+
as.EXPECT().NewListPublicIpAddressesParams().Return(aslp)
567+
as.EXPECT().ListPublicIpAddresses(aslp).Return(&cloudstack.ListPublicIpAddressesResponse{
568+
Count: 2, PublicIpAddresses: []*cloudstack.PublicIpAddress{{State: "Allocated"}, {State: "Free"}},
569+
}, nil)
512570
sos.EXPECT().
513571
GetServiceOfferingByName(dummies.CSMachine1.Spec.Offering.Name, gomock.Any()).
514572
Return(&cloudstack.ServiceOffering{

0 commit comments

Comments
 (0)