66
77 "github.com/gophercloud/gophercloud"
88 netext "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions"
9+ "github.com/gophercloud/gophercloud/openstack/networking/v2/subnets"
910 "github.com/gophercloud/utils/openstack/clientconfig"
11+ "github.com/pkg/errors"
1012 corev1 "k8s.io/api/core/v1"
1113 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1214 "k8s.io/apimachinery/pkg/runtime"
@@ -57,7 +59,7 @@ func Machines(clusterID string, config *types.InstallConfig, pool *types.Machine
5759 for idx := int64 (0 ); idx < total ; idx ++ {
5860 failureDomain := failureDomains [uint (idx )% uint (len (failureDomains ))]
5961
60- providerSpec := generateProviderSpec (
62+ providerSpec , err := generateProviderSpec (
6163 clusterID ,
6264 platform ,
6365 mpool ,
@@ -67,6 +69,9 @@ func Machines(clusterID string, config *types.InstallConfig, pool *types.Machine
6769 trunkSupport ,
6870 failureDomain ,
6971 )
72+ if err != nil {
73+ return nil , nil , err
74+ }
7075
7176 machine := machineapi.Machine {
7277 TypeMeta : metav1.TypeMeta {
@@ -92,7 +97,7 @@ func Machines(clusterID string, config *types.InstallConfig, pool *types.Machine
9297 machines = append (machines , machine )
9398 }
9499
95- machineSetProviderSpec := generateProviderSpec (
100+ machineSetProviderSpec , err := generateProviderSpec (
96101 clusterID ,
97102 platform ,
98103 mpool ,
@@ -102,6 +107,9 @@ func Machines(clusterID string, config *types.InstallConfig, pool *types.Machine
102107 trunkSupport ,
103108 machinev1.OpenStackFailureDomain {RootVolume : & machinev1.RootVolume {}},
104109 )
110+ if err != nil {
111+ return nil , nil , err
112+ }
105113
106114 replicas := int32 (total )
107115
@@ -156,25 +164,37 @@ func Machines(clusterID string, config *types.InstallConfig, pool *types.Machine
156164 return machines , controlPlaneMachineSet , nil
157165}
158166
159- func generateProviderSpec (clusterID string , platform * openstack.Platform , mpool * openstack.MachinePool , osImage string , role , userDataSecret string , trunkSupport bool , failureDomain machinev1.OpenStackFailureDomain ) * machinev1alpha1.OpenstackProviderSpec {
167+ func generateProviderSpec (clusterID string , platform * openstack.Platform , mpool * openstack.MachinePool , osImage string , role , userDataSecret string , trunkSupport bool , failureDomain machinev1.OpenStackFailureDomain ) ( * machinev1alpha1.OpenstackProviderSpec , error ) {
160168 var controlPlaneNetwork machinev1alpha1.NetworkParam
161169 additionalNetworks := make ([]machinev1alpha1.NetworkParam , 0 , len (mpool .AdditionalNetworkIDs ))
162170 primarySubnet := ""
163171
164172 if platform .ControlPlanePort != nil {
165173 var subnets []machinev1alpha1.SubnetParam
166174 controlPlanePort := platform .ControlPlanePort
175+ networkID := controlPlanePort .Network .ID
167176
168177 for _ , fixedIP := range controlPlanePort .FixedIPs {
169178 subnets = append (subnets , machinev1alpha1.SubnetParam {
170179 Filter : machinev1alpha1.SubnetFilter {ID : fixedIP .Subnet .ID , Name : fixedIP .Subnet .Name },
171180 })
172181 }
182+
183+ // In a dual-stack cluster, when network ID or Name is not specified, the network ID needs to
184+ // be discovered and added to the ProviderSpec for MAPO to create one unique Port with two addresses.
185+ var err error
186+ if networkID == "" && controlPlanePort .Network .Name == "" && len (controlPlanePort .FixedIPs ) == 2 {
187+ networkID , err = getNetworkFromSubnet (controlPlanePort .FixedIPs [0 ], platform .Cloud )
188+ if err != nil {
189+ return nil , err
190+ }
191+ }
192+
173193 controlPlaneNetwork = machinev1alpha1.NetworkParam {
174194 Subnets : subnets ,
175195 Filter : machinev1alpha1.Filter {
176196 Name : controlPlanePort .Network .Name ,
177- ID : controlPlanePort . Network . ID ,
197+ ID : networkID ,
178198 },
179199 }
180200 primarySubnet = controlPlanePort .FixedIPs [0 ].Subnet .ID
@@ -254,7 +274,7 @@ func generateProviderSpec(clusterID string, platform *openstack.Platform, mpool
254274 } else {
255275 spec .Image = osImage
256276 }
257- return & spec
277+ return & spec , nil
258278}
259279
260280// failureDomainIsEmpty returns true if the failure domain only contains nil or
@@ -380,6 +400,26 @@ func checkNetworkExtensionAvailability(cloud, alias string, opts *clientconfig.C
380400 return true , nil
381401}
382402
403+ func getNetworkFromSubnet (fixedIP openstack.FixedIP , cloud string ) (string , error ) {
404+ opts := openstackdefaults .DefaultClientOpts (cloud )
405+ conn , err := openstackdefaults .NewServiceClient ("network" , opts )
406+ if err != nil {
407+ return "" , err
408+ }
409+ page , err := subnets .List (conn , subnets.ListOpts {Name : fixedIP .Subnet .Name , ID : fixedIP .Subnet .ID }).AllPages ()
410+ if err != nil {
411+ return "" , errors .Wrap (err , "failed to get subnet list" )
412+ }
413+ subnetList , err := subnets .ExtractSubnets (page )
414+ if err != nil {
415+ return "" , errors .Wrap (err , "failed to extract subnets list" )
416+ }
417+ if len (subnetList ) == 0 {
418+ return "" , errors .New ("subnet not found" )
419+ }
420+ return subnetList [0 ].NetworkID , nil
421+ }
422+
383423// ConfigMasters sets the PublicIP flag and assigns a set of load balancers to the given machines
384424func ConfigMasters (machines []machineapi.Machine , clusterID string ) {
385425 /*for _, machine := range machines {
0 commit comments