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  }