github.com/openshift/installer@v1.4.17/pkg/asset/quota/gcp/gcp.go (about) 1 package gcp 2 3 import ( 4 "fmt" 5 "sort" 6 "strconv" 7 "strings" 8 9 machineapi "github.com/openshift/api/machine/v1beta1" 10 "github.com/openshift/installer/pkg/quota" 11 "github.com/openshift/installer/pkg/types" 12 ) 13 14 // Constraints returns a list of quota constraints based on the InstallConfig. 15 // These constraints can be used to check if there is enough quota for creating a cluster 16 // for the isntall config. 17 func Constraints(client *Client, config *types.InstallConfig, controlPlanes []machineapi.Machine, computes []machineapi.MachineSet) []quota.Constraint { 18 ctrplConfigs := make([]*machineapi.GCPMachineProviderSpec, len(controlPlanes)) 19 for i, m := range controlPlanes { 20 ctrplConfigs[i] = m.Spec.ProviderSpec.Value.Object.(*machineapi.GCPMachineProviderSpec) 21 } 22 computeReplicas := make([]int64, len(computes)) 23 computeConfigs := make([]*machineapi.GCPMachineProviderSpec, len(computes)) 24 for i, w := range computes { 25 computeReplicas[i] = int64(*w.Spec.Replicas) 26 computeConfigs[i] = w.Spec.Template.Spec.ProviderSpec.Value.Object.(*machineapi.GCPMachineProviderSpec) 27 } 28 29 var ret []quota.Constraint 30 for _, gen := range []constraintGenerator{ 31 network(config), 32 apiExternal(config), 33 apiInternal(config), 34 controlPlane(client, config, ctrplConfigs), 35 compute(client, config, computeReplicas, computeConfigs), 36 others, 37 } { 38 ret = append(ret, gen()...) 39 } 40 return aggregate(ret) 41 } 42 43 func aggregate(quotas []quota.Constraint) []quota.Constraint { 44 sort.SliceStable(quotas, func(i, j int) bool { 45 return quotas[i].Name < quotas[j].Name 46 }) 47 48 i := 0 49 for j := 1; j < len(quotas); j++ { 50 if quotas[i].Name == quotas[j].Name && quotas[i].Region == quotas[j].Region { 51 quotas[i].Count += quotas[j].Count 52 } else { 53 i++ 54 if i != j { 55 quotas[i] = quotas[j] 56 } 57 } 58 } 59 return quotas[:i+1] 60 } 61 62 // constraintGenerator generates a list of constraints. 63 type constraintGenerator func() []quota.Constraint 64 65 func network(config *types.InstallConfig) func() []quota.Constraint { 66 return func() []quota.Constraint { 67 net := []quota.Constraint{{ 68 Name: "compute.googleapis.com/networks", 69 Region: "global", 70 Count: 1, 71 }, { 72 Name: "compute.googleapis.com/subnetworks", 73 Region: "global", 74 Count: 2, 75 }, { 76 Name: "compute.googleapis.com/routers", 77 Region: "global", 78 Count: 1, 79 }} 80 81 firewalls := []quota.Constraint{{ 82 Name: "compute.googleapis.com/firewalls", 83 Region: "global", 84 Count: 6, 85 }} 86 87 if len(config.Platform.GCP.Network) > 0 { 88 return firewalls 89 } 90 return append(net, firewalls...) 91 } 92 } 93 94 func apiExternal(config *types.InstallConfig) func() []quota.Constraint { 95 return func() []quota.Constraint { 96 if config.Publish == types.InternalPublishingStrategy { 97 return nil 98 } 99 return []quota.Constraint{{ 100 Name: "compute.googleapis.com/health_checks", 101 Region: "global", 102 Count: 1, 103 }, { 104 Name: "compute.googleapis.com/forwarding_rules", 105 Region: "global", 106 Count: 1, 107 }, { 108 Name: "compute.googleapis.com/target_pools", 109 Region: "global", 110 Count: 1, 111 }, { 112 Name: "compute.googleapis.com/regional_static_addresses", 113 Region: config.Platform.GCP.Region, 114 Count: 1, 115 }} 116 } 117 } 118 119 func apiInternal(config *types.InstallConfig) func() []quota.Constraint { 120 return func() []quota.Constraint { 121 return []quota.Constraint{{ 122 Name: "compute.googleapis.com/health_checks", 123 Region: "global", 124 Count: 1, 125 }, { 126 Name: "compute.googleapis.com/forwarding_rules", 127 Region: "global", 128 Count: 1, 129 }, { 130 Name: "compute.googleapis.com/backend_services", 131 Region: "global", 132 Count: 1, 133 }, { 134 Name: "compute.googleapis.com/regional_static_addresses", 135 Region: config.Platform.GCP.Region, 136 Count: 1, 137 }} 138 } 139 } 140 141 func controlPlane(client MachineTypeGetter, config *types.InstallConfig, machines []*machineapi.GCPMachineProviderSpec) func() []quota.Constraint { 142 return func() []quota.Constraint { 143 var ret []quota.Constraint 144 for _, m := range machines { 145 q := machineTypeToQuota(client, m.Zone, m.MachineType) 146 q.Region = config.Platform.GCP.Region 147 ret = append(ret, q) 148 } 149 150 ret = append(ret, quota.Constraint{ 151 Name: "iam.googleapis.com/quota/service-account-count", 152 Region: "global", 153 Count: 1, 154 }) 155 return ret 156 } 157 } 158 159 func compute(client MachineTypeGetter, config *types.InstallConfig, replicas []int64, machines []*machineapi.GCPMachineProviderSpec) func() []quota.Constraint { 160 return func() []quota.Constraint { 161 var ret []quota.Constraint 162 for idx, m := range machines { 163 q := machineTypeToQuota(client, m.Zone, m.MachineType) 164 q.Count = q.Count * replicas[idx] 165 q.Region = config.Platform.GCP.Region 166 ret = append(ret, q) 167 } 168 169 ret = append(ret, quota.Constraint{ 170 Name: "iam.googleapis.com/quota/service-account-count", 171 Region: "global", 172 Count: 1, 173 }) 174 return ret 175 } 176 } 177 178 func others() []quota.Constraint { 179 return []quota.Constraint{{ 180 Name: "compute.googleapis.com/images", 181 Region: "global", 182 Count: 1, 183 }, { 184 Name: "iam.googleapis.com/quota/service-account-count", 185 Region: "global", 186 Count: 3, 187 }} 188 } 189 190 func machineTypeToQuota(client MachineTypeGetter, zone string, machineType string) quota.Constraint { 191 var name string 192 class := strings.SplitN(machineType, "-", 2)[0] 193 switch class { 194 case "c2", "m1", "m2", "n2", "n2d": 195 name = fmt.Sprintf("compute.googleapis.com/%s_cpus", class) 196 default: 197 name = "compute.googleapis.com/cpus" 198 } 199 200 info, err := client.GetMachineType(zone, machineType) 201 if err != nil { 202 return quota.Constraint{Name: name, Count: guessMachineCPUCount(machineType)} 203 } 204 return quota.Constraint{Name: name, Count: info.GuestCpus} 205 } 206 207 // the guess is based on https://cloud.google.com/compute/docs/machine-types 208 func guessMachineCPUCount(machineType string) int64 { 209 split := strings.Split(machineType, "-") 210 switch len(split) { 211 case 4: 212 if c, err := strconv.ParseInt(split[2], 10, 0); err == nil { 213 return c 214 } 215 case 3: 216 switch split[0] { 217 case "c2", "m1", "m2", "n1", "n2", "n2d", "e2": 218 if c, err := strconv.ParseInt(split[2], 10, 0); err == nil { 219 return c 220 } 221 } 222 case 2: 223 switch split[0] { 224 case "e2": 225 return 2 226 case "f1", "g1": 227 return 1 228 } 229 } 230 return 0 231 }