github.com/kyma-project/kyma-environment-broker@v0.0.1/internal/provider/azure_provider.go (about) 1 package provider 2 3 import ( 4 "math/big" 5 "math/rand" 6 "net/netip" 7 "strconv" 8 9 "github.com/kyma-project/kyma-environment-broker/internal/networking" 10 11 "github.com/kyma-project/control-plane/components/provisioner/pkg/gqlschema" 12 "github.com/kyma-project/kyma-environment-broker/internal" 13 "github.com/kyma-project/kyma-environment-broker/internal/broker" 14 "github.com/kyma-project/kyma-environment-broker/internal/ptr" 15 ) 16 17 const ( 18 DefaultAzureRegion = "eastus" 19 DefaultEuAccessAzureRegion = "switzerlandnorth" 20 DefaultAzureMultiZoneCount = 3 21 ) 22 23 var europeAzure = "westeurope" 24 var usAzure = "eastus" 25 var asiaAzure = "southeastasia" 26 27 var trialPurpose = "evaluation" 28 29 var toAzureSpecific = map[string]*string{ 30 string(broker.Europe): &europeAzure, 31 string(broker.Us): &usAzure, 32 string(broker.Asia): &asiaAzure, 33 } 34 35 type ( 36 AzureInput struct { 37 MultiZone bool 38 ControlPlaneFailureTolerance string 39 } 40 AzureLiteInput struct{} 41 AzureTrialInput struct { 42 PlatformRegionMapping map[string]string 43 } 44 AzureFreemiumInput struct{} 45 ) 46 47 func (p *AzureInput) Defaults() *gqlschema.ClusterConfigInput { 48 zonesCount := 1 49 if p.MultiZone { 50 zonesCount = DefaultAzureMultiZoneCount 51 } 52 var controlPlaneFailureTolerance *string = nil 53 if p.ControlPlaneFailureTolerance != "" { 54 controlPlaneFailureTolerance = &p.ControlPlaneFailureTolerance 55 } 56 return &gqlschema.ClusterConfigInput{ 57 GardenerConfig: &gqlschema.GardenerConfigInput{ 58 DiskType: ptr.String("Standard_LRS"), 59 VolumeSizeGb: ptr.Integer(50), 60 MachineType: "Standard_D4_v3", 61 Region: DefaultAzureRegion, 62 Provider: "azure", 63 WorkerCidr: networking.DefaultNodesCIDR, 64 AutoScalerMin: 3, 65 AutoScalerMax: 20, 66 MaxSurge: zonesCount, 67 MaxUnavailable: 0, 68 ProviderSpecificConfig: &gqlschema.ProviderSpecificInput{ 69 AzureConfig: &gqlschema.AzureProviderConfigInput{ 70 VnetCidr: networking.DefaultNodesCIDR, 71 AzureZones: generateAzureZones(networking.DefaultNodesCIDR, generateRandomAzureZones(zonesCount)), 72 EnableNatGateway: ptr.Bool(true), 73 }, 74 }, 75 ControlPlaneFailureTolerance: controlPlaneFailureTolerance, 76 }, 77 } 78 } 79 80 func (p *AzureInput) ApplyParameters(input *gqlschema.ClusterConfigInput, pp internal.ProvisioningParameters) { 81 if internal.IsEuAccess(pp.PlatformRegion) { 82 updateString(&input.GardenerConfig.Region, ptr.String(DefaultEuAccessAzureRegion)) 83 return 84 } 85 workerCidr := networking.DefaultNodesCIDR 86 if pp.Parameters.Networking != nil { 87 workerCidr = pp.Parameters.Networking.NodesCidr 88 } 89 input.GardenerConfig.WorkerCidr = workerCidr 90 input.GardenerConfig.ProviderSpecificConfig.AzureConfig.VnetCidr = workerCidr 91 zonesCount := 1 92 if p.MultiZone { 93 zonesCount = DefaultAzureMultiZoneCount 94 } 95 96 // explicit zones list is provided 97 if len(pp.Parameters.Zones) > 0 { 98 var zones []int 99 for _, inputZone := range pp.Parameters.Zones { 100 zone, err := strconv.Atoi(inputZone) 101 if err != nil || zone < 1 || zone > 3 { 102 continue 103 } 104 zones = append(zones, zone) 105 } 106 input.GardenerConfig.ProviderSpecificConfig.AzureConfig.AzureZones = generateAzureZones(workerCidr, zones) 107 } else { 108 input.GardenerConfig.ProviderSpecificConfig.AzureConfig.AzureZones = generateAzureZones(workerCidr, generateRandomAzureZones(zonesCount)) 109 } 110 } 111 112 func (p *AzureInput) Profile() gqlschema.KymaProfile { 113 return gqlschema.KymaProfileProduction 114 } 115 116 func (p *AzureInput) Provider() internal.CloudProvider { 117 return internal.Azure 118 } 119 120 func (p *AzureLiteInput) Defaults() *gqlschema.ClusterConfigInput { 121 return &gqlschema.ClusterConfigInput{ 122 GardenerConfig: &gqlschema.GardenerConfigInput{ 123 DiskType: ptr.String("Standard_LRS"), 124 VolumeSizeGb: ptr.Integer(50), 125 MachineType: "Standard_D4_v3", 126 Region: DefaultAzureRegion, 127 Provider: "azure", 128 WorkerCidr: networking.DefaultNodesCIDR, 129 AutoScalerMin: 2, 130 AutoScalerMax: 10, 131 MaxSurge: 1, 132 MaxUnavailable: 0, 133 ProviderSpecificConfig: &gqlschema.ProviderSpecificInput{ 134 AzureConfig: &gqlschema.AzureProviderConfigInput{ 135 VnetCidr: networking.DefaultNodesCIDR, 136 AzureZones: []*gqlschema.AzureZoneInput{ 137 { 138 Name: generateRandomAzureZone(), 139 Cidr: networking.DefaultNodesCIDR, 140 }, 141 }, 142 EnableNatGateway: ptr.Bool(true), 143 }, 144 }, 145 }, 146 } 147 } 148 149 func (p *AzureLiteInput) ApplyParameters(input *gqlschema.ClusterConfigInput, pp internal.ProvisioningParameters) { 150 if internal.IsEuAccess(pp.PlatformRegion) { 151 updateString(&input.GardenerConfig.Region, ptr.String(DefaultEuAccessAzureRegion)) 152 } 153 154 updateAzureSingleNodeWorkerCidr(input, pp) 155 } 156 157 func updateAzureSingleNodeWorkerCidr(input *gqlschema.ClusterConfigInput, pp internal.ProvisioningParameters) { 158 workerCIDR := networking.DefaultNodesCIDR 159 if pp.Parameters.Networking != nil { 160 workerCIDR = pp.Parameters.Networking.NodesCidr 161 } 162 input.GardenerConfig.WorkerCidr = workerCIDR 163 input.GardenerConfig.ProviderSpecificConfig.AzureConfig.VnetCidr = workerCIDR 164 input.GardenerConfig.ProviderSpecificConfig.AzureConfig.AzureZones[0].Cidr = workerCIDR 165 } 166 167 func (p *AzureLiteInput) Profile() gqlschema.KymaProfile { 168 return gqlschema.KymaProfileEvaluation 169 } 170 171 func (p *AzureLiteInput) Provider() internal.CloudProvider { 172 return internal.Azure 173 } 174 175 func (p *AzureTrialInput) Defaults() *gqlschema.ClusterConfigInput { 176 return azureTrialDefaults() 177 } 178 179 func azureTrialDefaults() *gqlschema.ClusterConfigInput { 180 return &gqlschema.ClusterConfigInput{ 181 GardenerConfig: &gqlschema.GardenerConfigInput{ 182 DiskType: ptr.String("Standard_LRS"), 183 VolumeSizeGb: ptr.Integer(50), 184 MachineType: "Standard_D4_v3", 185 Region: DefaultAzureRegion, 186 Provider: "azure", 187 WorkerCidr: networking.DefaultNodesCIDR, 188 AutoScalerMin: 1, 189 AutoScalerMax: 1, 190 MaxSurge: 1, 191 MaxUnavailable: 0, 192 Purpose: &trialPurpose, 193 ProviderSpecificConfig: &gqlschema.ProviderSpecificInput{ 194 AzureConfig: &gqlschema.AzureProviderConfigInput{ 195 VnetCidr: networking.DefaultNodesCIDR, 196 AzureZones: []*gqlschema.AzureZoneInput{ 197 { 198 Name: generateRandomAzureZone(), 199 Cidr: networking.DefaultNodesCIDR, 200 }, 201 }, 202 EnableNatGateway: ptr.Bool(false), 203 }, 204 }, 205 }, 206 } 207 } 208 209 func (p *AzureTrialInput) ApplyParameters(input *gqlschema.ClusterConfigInput, pp internal.ProvisioningParameters) { 210 params := pp.Parameters 211 212 if internal.IsEuAccess(pp.PlatformRegion) { 213 updateString(&input.GardenerConfig.Region, ptr.String(DefaultEuAccessAzureRegion)) 214 return 215 } 216 217 // read platform region if exists 218 if pp.PlatformRegion != "" { 219 abstractRegion, found := p.PlatformRegionMapping[pp.PlatformRegion] 220 if found { 221 r := toAzureSpecific[abstractRegion] 222 updateString(&input.GardenerConfig.Region, r) 223 } 224 } 225 226 if params.Region != nil && *params.Region != "" { 227 updateString(&input.GardenerConfig.Region, toAzureSpecific[*params.Region]) 228 } 229 230 updateAzureSingleNodeWorkerCidr(input, pp) 231 } 232 233 func (p *AzureTrialInput) Provider() internal.CloudProvider { 234 return internal.Azure 235 } 236 237 func (p *AzureTrialInput) Profile() gqlschema.KymaProfile { 238 return gqlschema.KymaProfileEvaluation 239 } 240 241 func (p *AzureFreemiumInput) Defaults() *gqlschema.ClusterConfigInput { 242 return azureTrialDefaults() 243 } 244 245 func (p *AzureFreemiumInput) ApplyParameters(input *gqlschema.ClusterConfigInput, params internal.ProvisioningParameters) { 246 updateSlice(&input.GardenerConfig.ProviderSpecificConfig.AzureConfig.Zones, params.Parameters.Zones) 247 } 248 249 func (p *AzureFreemiumInput) Profile() gqlschema.KymaProfile { 250 return gqlschema.KymaProfileEvaluation 251 } 252 253 func (p *AzureFreemiumInput) Provider() internal.CloudProvider { 254 return internal.Azure 255 } 256 257 func generateRandomAzureZone() int { 258 const ( 259 min = 1 260 max = 3 261 ) 262 263 // generates random number from 1-3 range 264 getRandomNumber := func() int { 265 return rand.Intn(max-min+1) + min 266 } 267 268 return getRandomNumber() 269 } 270 271 func generateRandomAzureZones(zonesCount int) []int { 272 zones := []int{1, 2, 3} 273 if zonesCount > 3 { 274 zonesCount = 3 275 } 276 277 rand.Shuffle(len(zones), func(i, j int) { zones[i], zones[j] = zones[j], zones[i] }) 278 return zones[:zonesCount] 279 } 280 281 func generateAzureZones(workerCidr string, zoneNames []int) []*gqlschema.AzureZoneInput { 282 var zones []*gqlschema.AzureZoneInput 283 284 cidr, _ := netip.ParsePrefix(workerCidr) 285 workerPrefixLength := cidr.Bits() + 3 286 workerPrefix, _ := cidr.Addr().Prefix(workerPrefixLength) 287 // delta - it is the difference between CIDRs of two zones: 288 // zone1: "10.250.0.0/19", 289 // zone2: "10.250.32.0/19", 290 delta := big.NewInt(1) 291 delta.Lsh(delta, uint(32-workerPrefixLength)) 292 293 // zoneIPValue - it is an integer, which is based on IP bytes 294 zoneIPValue := new(big.Int).SetBytes(workerPrefix.Addr().AsSlice()) 295 296 for _, name := range zoneNames { 297 zoneWorkerIP, _ := netip.AddrFromSlice(zoneIPValue.Bytes()) 298 zoneWorkerCidr := netip.PrefixFrom(zoneWorkerIP, workerPrefixLength) 299 zoneIPValue.Add(zoneIPValue, delta) 300 zones = append(zones, &gqlschema.AzureZoneInput{ 301 Name: name, 302 Cidr: zoneWorkerCidr.String(), 303 }) 304 } 305 return zones 306 }