@@ -2,20 +2,24 @@ package azure
22
33import (
44 "fmt"
5+ "slices"
56 "sort"
67
78 "github.com/pkg/errors"
89 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
910 "k8s.io/apimachinery/pkg/runtime"
11+ "k8s.io/apimachinery/pkg/util/sets"
1012
1113 clusterapi "github.com/openshift/api/machine/v1beta1"
14+ "github.com/openshift/installer/pkg/asset/installconfig"
1215 icazure "github.com/openshift/installer/pkg/asset/installconfig/azure"
1316 "github.com/openshift/installer/pkg/types"
1417 "github.com/openshift/installer/pkg/types/azure"
1518)
1619
1720// MachineSets returns a list of machinesets for a machinepool.
18- func MachineSets (clusterID string , config * types.InstallConfig , pool * types.MachinePool , osImage , role , userDataSecret string , capabilities map [string ]string , useImageGallery bool , subnetZones []string , session * icazure.Session ) ([]* clusterapi.MachineSet , error ) {
21+ func MachineSets (clusterID string , ic * installconfig.InstallConfig , pool * types.MachinePool , osImage , role , userDataSecret string , capabilities map [string ]string , useImageGallery bool , subnetZones []string , session * icazure.Session ) ([]* clusterapi.MachineSet , error ) {
22+ config := ic .Config
1923 if configPlatform := config .Platform .Name (); configPlatform != azure .Name {
2024 return nil , fmt .Errorf ("non-azure configuration: %q" , configPlatform )
2125 }
@@ -47,6 +51,27 @@ func MachineSets(clusterID string, config *types.InstallConfig, pool *types.Mach
4751 sort .Strings (azs )
4852 subnetIndex := - 1
4953 var machinesets []* clusterapi.MachineSet
54+
55+ if config .Azure .OutboundType == azure .NATGatewayMultiZoneOutboundType {
56+ return getMultiZoneMachineSets (multiZoneMachineSetInput {
57+ networkResourceGroup : networkResourceGroup ,
58+ virtualNetworkName : virtualNetworkName ,
59+ platform : platform ,
60+ mpool : mpool ,
61+ osImage : osImage ,
62+ userDataSecret : userDataSecret ,
63+ clusterID : clusterID ,
64+ role : role ,
65+ capabilities : capabilities ,
66+ useImageGallery : useImageGallery ,
67+ session : session ,
68+ subnetSpec : config .Azure .Subnets ,
69+ replicas : total ,
70+ ic : ic ,
71+ azs : azs ,
72+ pool : pool ,
73+ })
74+ }
5075 for idx , az := range azs {
5176 replicas := int32 (total / numOfAZs )
5277 if int64 (idx ) < total % numOfAZs {
@@ -102,3 +127,128 @@ func MachineSets(clusterID string, config *types.InstallConfig, pool *types.Mach
102127 }
103128 return machinesets , nil
104129}
130+
131+ type multiZoneMachineSetInput struct {
132+ networkResourceGroup string
133+ platform * azure.Platform
134+ mpool * azure.MachinePool
135+ osImage string
136+ userDataSecret string
137+ clusterID string
138+ role string
139+ capabilities map [string ]string
140+ useImageGallery bool
141+ session * icazure.Session
142+ virtualNetworkName string
143+ subnetSpec []azure.SubnetSpec
144+ replicas int64
145+ ic * installconfig.InstallConfig
146+ azs []string
147+ pool * types.MachinePool
148+ }
149+
150+ func getMultiZoneMachineSets (in multiZoneMachineSetInput ) ([]* clusterapi.MachineSet , error ) {
151+ // Deep copy metadata map.
152+ zoneSubnetmap := map [string ][]string {}
153+ subnetCount := 0
154+ // Filter for the zones the user provided for compute nodes.
155+ for key , value := range in .ic .Azure .ZonesSubnetMap {
156+ if slices .Contains (in .azs , key ) {
157+ zoneSubnetmap [key ] = sets .NewString (value ... ).List ()
158+ subnetCount += len (value )
159+ }
160+ }
161+ machineSets := []* clusterapi.MachineSet {}
162+ replicasToCreate := int32 (in .replicas )
163+ // Calculate the replicas per machine set.
164+ // This just first finds the nearest multiple of subnet count
165+ // then distributes the remainder across the machine sets one by one.
166+ // If there are 3 subnets and 8 replicas, first we would
167+ // set 8/3 = 2 replicas for each subnet (2,2,2) and distribute the
168+ // remaining machines (2) evenly to have (3,3,2).
169+ replicaPerSet := max (replicasToCreate / int32 (subnetCount ), 1 )
170+ remainder := replicasToCreate % int32 (subnetCount )
171+ if replicasToCreate < int32 (subnetCount ) {
172+ remainder = 0
173+ }
174+ numAZUsed := map [string ]int {}
175+ for _ , az := range in .azs {
176+ numAZUsed [az ] = 0
177+ }
178+
179+ // Iterate till we used up all the replicas mentioned.
180+ // Iterate through the zones provided and find a subnet to use.
181+ for replicasToCreate != 0 && len (zoneSubnetmap ) != 0 {
182+ for idx , az := range in .azs {
183+ if replicaPerSet == 0 || len (zoneSubnetmap ) == 0 {
184+ break
185+ }
186+ if _ , ok := zoneSubnetmap [az ]; ! ok {
187+ continue
188+ }
189+ subnet := zoneSubnetmap [az ][0 ]
190+ if len (zoneSubnetmap [az ]) == 1 {
191+ delete (zoneSubnetmap , az )
192+ } else {
193+ zoneSubnetmap [az ] = zoneSubnetmap [az ][1 :]
194+ }
195+ currentReplica := replicaPerSet
196+ if remainder != 0 {
197+ currentReplica ++
198+ remainder --
199+ }
200+ provider , err := provider (in .platform , in .mpool , in .osImage , in .userDataSecret , in .clusterID , in .role , & idx , in .capabilities , in .useImageGallery , in .session , in .networkResourceGroup , in .virtualNetworkName , subnet )
201+ if err != nil {
202+ return nil , errors .Wrap (err , "failed to create provider" )
203+ }
204+ name := fmt .Sprintf ("%s-%s-%s%s-%d" , in .clusterID , in .pool .Name , in .platform .Region , az , numAZUsed [az ])
205+ if numAZUsed [az ] == 0 {
206+ name = fmt .Sprintf ("%s-%s-%s%s" , in .clusterID , in .pool .Name , in .platform .Region , az )
207+ }
208+ numAZUsed [az ]++
209+ mset := & clusterapi.MachineSet {
210+ TypeMeta : metav1.TypeMeta {
211+ APIVersion : "machine.openshift.io/v1beta1" ,
212+ Kind : "MachineSet" ,
213+ },
214+ ObjectMeta : metav1.ObjectMeta {
215+ Namespace : "openshift-machine-api" ,
216+ Name : name ,
217+ Labels : map [string ]string {
218+ "machine.openshift.io/cluster-api-cluster" : in .clusterID ,
219+ "machine.openshift.io/cluster-api-machine-role" : in .role ,
220+ "machine.openshift.io/cluster-api-machine-type" : in .role ,
221+ },
222+ },
223+ Spec : clusterapi.MachineSetSpec {
224+ Replicas : & currentReplica ,
225+ Selector : metav1.LabelSelector {
226+ MatchLabels : map [string ]string {
227+ "machine.openshift.io/cluster-api-machineset" : name ,
228+ "machine.openshift.io/cluster-api-cluster" : in .clusterID ,
229+ },
230+ },
231+ Template : clusterapi.MachineTemplateSpec {
232+ ObjectMeta : clusterapi.ObjectMeta {
233+ Labels : map [string ]string {
234+ "machine.openshift.io/cluster-api-machineset" : name ,
235+ "machine.openshift.io/cluster-api-cluster" : in .clusterID ,
236+ "machine.openshift.io/cluster-api-machine-role" : in .role ,
237+ "machine.openshift.io/cluster-api-machine-type" : in .role ,
238+ },
239+ },
240+ Spec : clusterapi.MachineSpec {
241+ ProviderSpec : clusterapi.ProviderSpec {
242+ Value : & runtime.RawExtension {Object : provider },
243+ },
244+ // we don't need to set Versions, because we control those via cluster operators.
245+ },
246+ },
247+ },
248+ }
249+ machineSets = append (machineSets , mset )
250+ replicasToCreate -= currentReplica
251+ }
252+ }
253+ return machineSets , nil
254+ }
0 commit comments