sigs.k8s.io/cluster-api-provider-azure@v1.14.3/azure/services/virtualnetworks/virtualnetworks.go (about)

     1  /*
     2  Copyright 2019 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 virtualnetworks
    18  
    19  import (
    20  	"context"
    21  
    22  	asonetworkv1 "github.com/Azure/azure-service-operator/v2/api/network/v1api20201101"
    23  	"github.com/Azure/azure-service-operator/v2/pkg/common/labels"
    24  	"github.com/pkg/errors"
    25  	"k8s.io/utils/ptr"
    26  	infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1"
    27  	"sigs.k8s.io/cluster-api-provider-azure/azure"
    28  	"sigs.k8s.io/cluster-api-provider-azure/azure/converters"
    29  	"sigs.k8s.io/cluster-api-provider-azure/azure/services/aso"
    30  	"sigs.k8s.io/controller-runtime/pkg/client"
    31  )
    32  
    33  const serviceName = "virtualnetworks"
    34  
    35  // VNetScope defines the scope interface for a virtual network service.
    36  type VNetScope interface {
    37  	aso.Scope
    38  	Vnet() *infrav1.VnetSpec
    39  	VNetSpec() azure.ASOResourceSpecGetter[*asonetworkv1.VirtualNetwork]
    40  	UpdateSubnetCIDRs(string, []string)
    41  }
    42  
    43  // New creates a new service.
    44  func New(scope VNetScope) *aso.Service[*asonetworkv1.VirtualNetwork, VNetScope] {
    45  	svc := aso.NewService[*asonetworkv1.VirtualNetwork](serviceName, scope)
    46  	svc.Specs = []azure.ASOResourceSpecGetter[*asonetworkv1.VirtualNetwork]{scope.VNetSpec()}
    47  	svc.ConditionType = infrav1.VNetReadyCondition
    48  	svc.PostCreateOrUpdateResourceHook = postCreateOrUpdateResourceHook
    49  	return svc
    50  }
    51  
    52  func postCreateOrUpdateResourceHook(ctx context.Context, scope VNetScope, existingVnet *asonetworkv1.VirtualNetwork, err error) error {
    53  	if err != nil {
    54  		return err
    55  	}
    56  
    57  	vnet := scope.Vnet()
    58  	vnet.ID = ptr.Deref(existingVnet.Status.Id, "")
    59  	vnet.Tags = existingVnet.Status.Tags
    60  
    61  	// Update the subnet CIDRs if they already exist.
    62  	// This makes sure the subnet CIDRs are up to date and there are no validation errors when updating the VNet.
    63  	// Subnets that are not part of this cluster spec are silently ignored.
    64  	subnets := &asonetworkv1.VirtualNetworksSubnetList{}
    65  	err = scope.GetClient().List(ctx, subnets,
    66  		client.InNamespace(existingVnet.Namespace),
    67  		client.MatchingLabels{labels.OwnerNameLabel: existingVnet.Name},
    68  	)
    69  	if err != nil {
    70  		return errors.Wrap(err, "failed to list subnets")
    71  	}
    72  	for _, subnet := range subnets.Items {
    73  		scope.UpdateSubnetCIDRs(subnet.AzureName(), converters.GetSubnetAddresses(subnet))
    74  	}
    75  	// Only update the vnet's CIDRBlocks when we also updated subnets' since the vnet is created before
    76  	// subnets to prevent an updated vnet CIDR from invalidating subnet CIDRs that were defaulted and do not
    77  	// exist yet.
    78  	if len(subnets.Items) > 0 && existingVnet.Status.AddressSpace != nil {
    79  		vnet.CIDRBlocks = existingVnet.Status.AddressSpace.AddressPrefixes
    80  	}
    81  
    82  	return nil
    83  }