sigs.k8s.io/cluster-api-provider-azure@v1.14.3/api/v1beta1/azureclustertemplate_validation.go (about) 1 /* 2 Copyright 2022 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package v1beta1 18 19 import ( 20 "fmt" 21 22 apierrors "k8s.io/apimachinery/pkg/api/errors" 23 "k8s.io/apimachinery/pkg/runtime/schema" 24 "k8s.io/apimachinery/pkg/util/validation/field" 25 "sigs.k8s.io/controller-runtime/pkg/webhook/admission" 26 ) 27 28 func (c *AzureClusterTemplate) validateClusterTemplate() (admission.Warnings, error) { 29 var allErrs field.ErrorList 30 allErrs = append(allErrs, c.validateClusterTemplateSpec()...) 31 32 if len(allErrs) == 0 { 33 return nil, nil 34 } 35 36 return nil, apierrors.NewInvalid( 37 schema.GroupKind{Group: "infrastructure.cluster.x-k8s.io", Kind: "AzureClusterTemplate"}, 38 c.Name, allErrs) 39 } 40 41 func (c *AzureClusterTemplate) validateClusterTemplateSpec() field.ErrorList { 42 var allErrs field.ErrorList 43 44 allErrs = append(allErrs, validateVnetCIDR( 45 c.Spec.Template.Spec.NetworkSpec.Vnet.CIDRBlocks, 46 field.NewPath("spec").Child("template").Child("spec"). 47 Child("networkSpec").Child("vnet").Child("cidrBlocks"))...) 48 49 allErrs = append(allErrs, validateSubnetTemplates( 50 c.Spec.Template.Spec.NetworkSpec.Subnets, 51 c.Spec.Template.Spec.NetworkSpec.Vnet, 52 field.NewPath("spec").Child("template").Child("spec").Child("networkSpec").Child("subnets"), 53 )...) 54 55 allErrs = append(allErrs, c.validateAPIServerLB( 56 field.NewPath("spec").Child("template").Child("spec").Child("networkSpec").Child("apiServerLB"), 57 )...) 58 59 allErrs = append(allErrs, c.validateNetworkSpec()...) 60 61 allErrs = append(allErrs, c.validateControlPlaneOutboundLB()...) 62 63 allErrs = append(allErrs, c.validatePrivateDNSZoneName()...) 64 65 return allErrs 66 } 67 68 func (c *AzureClusterTemplate) validateNetworkSpec() field.ErrorList { 69 var allErrs field.ErrorList 70 71 var needOutboundLB bool 72 networkSpec := c.Spec.Template.Spec.NetworkSpec 73 for _, subnet := range networkSpec.Subnets { 74 if subnet.Role == SubnetNode && subnet.IsIPv6Enabled() { 75 needOutboundLB = true 76 break 77 } 78 } 79 if needOutboundLB { 80 allErrs = append(allErrs, c.validateNodeOutboundLB()...) 81 } 82 83 return allErrs 84 } 85 86 func validateSubnetTemplates(subnets SubnetTemplatesSpec, vnet VnetTemplateSpec, fld *field.Path) field.ErrorList { 87 var allErrs field.ErrorList 88 subnetNames := make(map[string]bool, len(subnets)) 89 requiredSubnetRoles := map[string]bool{ 90 "control-plane": false, 91 "node": false, 92 } 93 94 for i, subnet := range subnets { 95 if err := validateSubnetName(subnet.Name, fld.Index(i).Child("name")); err != nil { 96 allErrs = append(allErrs, err) 97 } 98 if _, ok := subnetNames[subnet.Name]; ok { 99 allErrs = append(allErrs, field.Duplicate(fld, subnet.Name)) 100 } 101 subnetNames[subnet.Name] = true 102 for role := range requiredSubnetRoles { 103 if role == string(subnet.Role) { 104 requiredSubnetRoles[role] = true 105 } 106 } 107 for j, rule := range subnet.SecurityGroup.SecurityRules { 108 if err := validateSecurityRule( 109 rule, 110 fld.Index(i).Child("securityGroup").Child("securityGroup").Child("securityRules").Index(j), 111 ); err != nil { 112 allErrs = append(allErrs, err...) 113 } 114 } 115 allErrs = append(allErrs, validateSubnetCIDR(subnet.CIDRBlocks, vnet.CIDRBlocks, fld.Index(i).Child("cidrBlocks"))...) 116 } 117 for k, v := range requiredSubnetRoles { 118 if !v { 119 allErrs = append(allErrs, field.Required(fld, 120 fmt.Sprintf("required role %s not included in provided subnets", k))) 121 } 122 } 123 return allErrs 124 } 125 126 func (c *AzureClusterTemplate) validateAPIServerLB(apiServerLBPath *field.Path) field.ErrorList { 127 var allErrs field.ErrorList 128 lb := c.Spec.Template.Spec.NetworkSpec.APIServerLB 129 allErrs = append(allErrs, validateClassSpecForAPIServerLB(lb, nil, apiServerLBPath)...) 130 return allErrs 131 } 132 133 func (c *AzureClusterTemplate) validateNodeOutboundLB() field.ErrorList { 134 var allErrs field.ErrorList 135 136 fldPath := field.NewPath("spec").Child("template").Child("spec").Child("networkSpec").Child("nodeOutboundLB") 137 apiserverLB := c.Spec.Template.Spec.NetworkSpec.APIServerLB 138 lb := c.Spec.Template.Spec.NetworkSpec.NodeOutboundLB 139 140 allErrs = append(allErrs, validateClassSpecForNodeOutboundLB(lb, nil, apiserverLB, fldPath)...) 141 142 return allErrs 143 } 144 145 func (c *AzureClusterTemplate) validateControlPlaneOutboundLB() field.ErrorList { 146 var allErrs field.ErrorList 147 148 fldPath := field.NewPath("spec").Child("template").Child("spec").Child("networkSpec").Child("controlPlaneOutboundLB") 149 apiserverLB := c.Spec.Template.Spec.NetworkSpec.APIServerLB 150 lb := c.Spec.Template.Spec.NetworkSpec.ControlPlaneOutboundLB 151 152 allErrs = append(allErrs, validateClassSpecForControlPlaneOutboundLB(lb, apiserverLB, fldPath)...) 153 154 return allErrs 155 } 156 157 func (c *AzureClusterTemplate) validatePrivateDNSZoneName() field.ErrorList { 158 var allErrs field.ErrorList 159 160 fldPath := field.NewPath("spec").Child("template").Child("spec").Child("networkSpec").Child("privateDNSZoneName") 161 networkSpec := c.Spec.Template.Spec.NetworkSpec 162 163 allErrs = append(allErrs, validatePrivateDNSZoneName( 164 networkSpec.PrivateDNSZoneName, 165 networkSpec.APIServerLB.Type, 166 fldPath, 167 )...) 168 169 return allErrs 170 }