Skip to content

Commit 380f8d2

Browse files
committed
Modify OpenStackCluster.Spec.Network API
For the BYO scenario, when the `OpenStackCluster.Spec.Network` is not specified the query to OpenStack will return all the Networks available in the cloud and fail the reconciliation. To avoid this, if any Subnets were specified under `OpenStackCluster.Spec.Subnets` this can be used to identify which Network to use.
1 parent 05571b9 commit 380f8d2

File tree

5 files changed

+134
-23
lines changed

5 files changed

+134
-23
lines changed

controllers/openstackcluster_controller.go

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"reflect"
2424
"time"
2525

26+
"github.com/gophercloud/gophercloud/openstack/networking/v2/subnets"
2627
corev1 "k8s.io/api/core/v1"
2728
apierrors "k8s.io/apimachinery/pkg/api/errors"
2829
"k8s.io/client-go/tools/record"
@@ -506,26 +507,33 @@ func reconcileNetworkComponents(scope scope.Scope, cluster *clusterv1.Cluster, o
506507
handleUpdateOSCError(openStackCluster, fmt.Errorf("failed to find any network"))
507508
return fmt.Errorf("failed to find any network")
508509
}
509-
if len(networkList) > 1 {
510-
handleUpdateOSCError(openStackCluster, fmt.Errorf("found multiple networks (result: %v)", networkList))
511-
return fmt.Errorf("found multiple networks (result: %v)", networkList)
512-
}
513510
if openStackCluster.Status.Network == nil {
514511
openStackCluster.Status.Network = &infrav1.NetworkStatusWithSubnets{}
515512
}
516-
openStackCluster.Status.Network.ID = networkList[0].ID
517-
openStackCluster.Status.Network.Name = networkList[0].Name
518-
openStackCluster.Status.Network.Tags = networkList[0].Tags
513+
if len(networkList) == 1 {
514+
networking.ConvertOpenStackNetworkToCAPONetwork(openStackCluster, &networkList[0])
515+
}
519516

520-
subnets, err := filterSubnets(networkingService, openStackCluster)
517+
filteredSubnets, err := filterSubnets(networkingService, openStackCluster)
521518
if err != nil {
522519
return err
523520
}
524521

522+
var subnets []infrav1.Subnet
523+
for subnet := range filteredSubnets {
524+
subnets = networking.ConvertOpenStackSubnetToCAPOSubnet(subnets, &filteredSubnets[subnet])
525+
}
526+
525527
if err := utils.ValidateSubnets(subnets); err != nil {
526528
return err
527529
}
528530
openStackCluster.Status.Network.Subnets = subnets
531+
532+
// If network is not yet populated on the Status, use networkID defined in the filtered subnets.
533+
err = networkingService.PopulateCAPONetworkFromSubnet(filteredSubnets, openStackCluster)
534+
if err != nil {
535+
return err
536+
}
529537
} else {
530538
err := networkingService.ReconcileNetwork(openStackCluster, clusterName)
531539
if err != nil {
@@ -674,18 +682,23 @@ func handleUpdateOSCError(openstackCluster *infrav1.OpenStackCluster, message er
674682
}
675683

676684
// filterSubnets retrieves the subnets based on the Subnet filters specified on OpenstackCluster.
677-
func filterSubnets(networkingService *networking.Service, openStackCluster *infrav1.OpenStackCluster) ([]infrav1.Subnet, error) {
678-
var subnets []infrav1.Subnet
685+
func filterSubnets(networkingService *networking.Service, openStackCluster *infrav1.OpenStackCluster) ([]subnets.Subnet, error) {
686+
var filteredSubnets []subnets.Subnet
687+
var err error
679688
openStackClusterSubnets := openStackCluster.Spec.Subnets
680-
if openStackCluster.Status.Network == nil {
681-
return nil, nil
689+
networkID := ""
690+
if openStackCluster.Status.Network != nil {
691+
networkID = openStackCluster.Status.Network.ID
682692
}
683-
networkID := openStackCluster.Status.Network.ID
693+
684694
if len(openStackClusterSubnets) == 0 {
695+
if networkID == "" {
696+
return nil, nil
697+
}
685698
empty := &infrav1.SubnetFilter{}
686699
listOpt := empty.ToListOpt()
687700
listOpt.NetworkID = networkID
688-
filteredSubnets, err := networkingService.GetSubnetsByFilter(listOpt)
701+
filteredSubnets, err = networkingService.GetSubnetsByFilter(listOpt)
689702
if err != nil {
690703
err = fmt.Errorf("failed to find subnets: %w", err)
691704
if errors.Is(err, networking.ErrFilterMatch) {
@@ -696,9 +709,6 @@ func filterSubnets(networkingService *networking.Service, openStackCluster *infr
696709
if len(filteredSubnets) > 2 {
697710
return nil, fmt.Errorf("more than two subnets found in the Network. Specify the subnets in the OpenStackCluster.Spec instead")
698711
}
699-
for subnet := range filteredSubnets {
700-
subnets = networkingService.ConvertOpenStackSubnetToCAPOSubnet(subnets, &filteredSubnets[subnet])
701-
}
702712
} else {
703713
for subnet := range openStackClusterSubnets {
704714
filteredSubnet, err := networkingService.GetNetworkSubnetByFilter(networkID, &openStackClusterSubnets[subnet])
@@ -709,8 +719,8 @@ func filterSubnets(networkingService *networking.Service, openStackCluster *infr
709719
}
710720
return nil, err
711721
}
712-
subnets = networkingService.ConvertOpenStackSubnetToCAPOSubnet(subnets, filteredSubnet)
722+
filteredSubnets = append(filteredSubnets, *filteredSubnet)
713723
}
714724
}
715-
return subnets, nil
725+
return filteredSubnets, nil
716726
}

controllers/openstackcluster_controller_test.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,56 @@ var _ = Describe("OpenStackCluster controller", func() {
518518
Expect(err).To(BeNil())
519519
Expect(len(testCluster.Status.Network.Subnets)).To(Equal(2))
520520
})
521+
522+
It("should allow fetch network by subnet", func() {
523+
const clusterNetworkID = "6c90b532-7ba0-418a-a276-5ae55060b5b0"
524+
const additionalNetworkID = "e2407c18-c4e7-4d3d-befa-8eec5d8756f2"
525+
const clusterSubnetID = "cad5a91a-36de-4388-823b-b0cc82cadfdc"
526+
527+
testCluster.SetName("subnet-filtering")
528+
testCluster.Spec = infrav1.OpenStackClusterSpec{
529+
DisableAPIServerFloatingIP: true,
530+
APIServerFixedIP: "10.0.0.1",
531+
DisableExternalNetwork: true,
532+
Subnets: []infrav1.SubnetFilter{
533+
{ID: clusterSubnetID},
534+
},
535+
}
536+
err := k8sClient.Create(ctx, testCluster)
537+
Expect(err).To(BeNil())
538+
err = k8sClient.Create(ctx, capiCluster)
539+
Expect(err).To(BeNil())
540+
scope, err := mockScopeFactory.NewClientScopeFromCluster(ctx, k8sClient, testCluster, nil, logr.Discard())
541+
Expect(err).To(BeNil())
542+
543+
networkClientRecorder := mockScopeFactory.NetworkClient.EXPECT()
544+
545+
// Fetch cluster network
546+
networkClientRecorder.ListNetwork(&networks.ListOpts{}).Return([]networks.Network{
547+
{
548+
ID: clusterNetworkID,
549+
},
550+
{
551+
ID: additionalNetworkID,
552+
},
553+
}, nil)
554+
555+
// Fetching cluster subnets should be filtered by cluster network id
556+
networkClientRecorder.GetSubnet(clusterSubnetID).Return(&subnets.Subnet{
557+
ID: clusterSubnetID,
558+
CIDR: "192.168.0.0/24",
559+
NetworkID: clusterNetworkID,
560+
}, nil)
561+
562+
// Fetch cluster network using the NetworkID from the filtered Subnets
563+
networkClientRecorder.GetNetwork(clusterNetworkID).Return(&networks.Network{
564+
ID: clusterNetworkID,
565+
}, nil)
566+
567+
err = reconcileNetworkComponents(scope, capiCluster, testCluster)
568+
Expect(err).To(BeNil())
569+
Expect(testCluster.Status.Network.ID).To(Equal(clusterNetworkID))
570+
})
521571
})
522572

523573
func createRequestFromOSCluster(openStackCluster *infrav1.OpenStackCluster) reconcile.Request {

docs/book/src/topics/crd-changes/v1alpha7-to-v1alpha8.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,4 +176,9 @@ In v1alpha8, this will be automatically converted to:
176176

177177
`Subnets` allows specifications of maximum two `SubnetFilter` one being IPv4 and the other IPv6. Both subnets must be on the same network. Any filtered subnets will be added to `OpenStackCluster.Status.Network.Subnets`.
178178

179-
When subnets are not specified on `OpenStackCluster` and only the network is, the network is used to identify the subnets to use. If more than two subnets exist in the network, the user must specify which ones to use by defining the `OpenStackCluster.Spec.Subnets` field.
179+
When subnets are not specified on `OpenStackCluster` and only the network is, the network is used to identify the subnets to use. If more than two subnets exist in the network, the user must specify which ones to use by defining the `OpenStackCluster.Spec.Subnets` field.
180+
181+
182+
#### ⚠️ Change to network
183+
184+
In v1alpha8, when the `OpenStackCluster.Spec.Network` is not defined, the `Subnets` are now used to identify the `Network`.

pkg/cloud/services/networking/network.go

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ func getNetworkName(clusterName string) string {
386386

387387
// ConvertOpenStackSubnetToCAPOSubnet converts an OpenStack subnet to a capo subnet and adds to a slice.
388388
// It returns the slice with the converted subnet.
389-
func (s *Service) ConvertOpenStackSubnetToCAPOSubnet(subnets []infrav1.Subnet, filteredSubnet *subnets.Subnet) []infrav1.Subnet {
389+
func ConvertOpenStackSubnetToCAPOSubnet(subnets []infrav1.Subnet, filteredSubnet *subnets.Subnet) []infrav1.Subnet {
390390
subnets = append(subnets, infrav1.Subnet{
391391
ID: filteredSubnet.ID,
392392
Name: filteredSubnet.Name,
@@ -395,3 +395,28 @@ func (s *Service) ConvertOpenStackSubnetToCAPOSubnet(subnets []infrav1.Subnet, f
395395
})
396396
return subnets
397397
}
398+
399+
// ConvertOpenStackNetworkToCAPONetwork converts an OpenStack network to a capo network.
400+
// It returns the converted subnet.
401+
func ConvertOpenStackNetworkToCAPONetwork(openStackCluster *infrav1.OpenStackCluster, network *networks.Network) {
402+
openStackCluster.Status.Network.ID = network.ID
403+
openStackCluster.Status.Network.Name = network.Name
404+
openStackCluster.Status.Network.Tags = network.Tags
405+
}
406+
407+
// PopulateCAPONetworkFromSubnet gets a network based on the networkID of the subnets and converts it to the CAPO format.
408+
// It returns an error in case it failed to retrieve the network.
409+
func (s *Service) PopulateCAPONetworkFromSubnet(subnets []subnets.Subnet, openStackCluster *infrav1.OpenStackCluster) error {
410+
if openStackCluster.Status.Network.ID == "" && len(subnets) > 0 {
411+
if len(subnets) > 1 && subnets[0].NetworkID != subnets[1].NetworkID {
412+
return fmt.Errorf("unable to identify the Network to use. NetworkID from Subnets differ: %s, %s", subnets[0].NetworkID, subnets[1].NetworkID)
413+
}
414+
415+
network, err := s.client.GetNetwork(subnets[0].NetworkID)
416+
if err != nil {
417+
return err
418+
}
419+
ConvertOpenStackNetworkToCAPONetwork(openStackCluster, network)
420+
}
421+
return nil
422+
}

pkg/cloud/services/networking/network_test.go

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -440,8 +440,7 @@ func Test_ConvertOpenStackSubnetToCAPOSubnet(t *testing.T) {
440440
Tags: []string{"tag3", "tag4"},
441441
}
442442

443-
s := Service{}
444-
result := s.ConvertOpenStackSubnetToCAPOSubnet(caposubnets, filteredSubnet)
443+
result := ConvertOpenStackSubnetToCAPOSubnet(caposubnets, filteredSubnet)
445444

446445
expected := []infrav1.Subnet{
447446
{
@@ -462,3 +461,25 @@ func Test_ConvertOpenStackSubnetToCAPOSubnet(t *testing.T) {
462461
t.Errorf("ConvertOpenStackSubnetToCAPOSubnet() = %v, want %v", result, expected)
463462
}
464463
}
464+
465+
func Test_ConvertOpenStackNetworkToCAPONetwork(t *testing.T) {
466+
openStackCluster := &infrav1.OpenStackCluster{}
467+
openStackCluster.Status.Network = &infrav1.NetworkStatusWithSubnets{}
468+
469+
filterednetwork := &networks.Network{
470+
ID: "network1",
471+
Name: "network1",
472+
Tags: []string{"tag1", "tag2"},
473+
}
474+
475+
ConvertOpenStackNetworkToCAPONetwork(openStackCluster, filterednetwork)
476+
expected := infrav1.NetworkStatus{
477+
ID: "network1",
478+
Name: "network1",
479+
Tags: []string{"tag1", "tag2"},
480+
}
481+
482+
if !reflect.DeepEqual(openStackCluster.Status.Network.NetworkStatus, expected) {
483+
t.Errorf("ConvertOpenStackNetworkToCAPONetwork() = %v, want %v", openStackCluster.Status.Network.NetworkStatus, expected)
484+
}
485+
}

0 commit comments

Comments
 (0)