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 }