Skip to content

Commit 31a7780

Browse files
authored
Merge pull request #114 from spectrocloud/spectro-v1.18.0-private-dns
Support for Azure Private DNS Zone to be present in any resource group
2 parents 6d749ad + fc8f260 commit 31a7780

9 files changed

+231
-4
lines changed

api/v1beta1/azurecluster_validation.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ func validateNetworkSpec(controlPlaneEnabled bool, networkSpec NetworkSpec, old
204204
lbType = networkSpec.APIServerLB.Type
205205
}
206206
allErrs = append(allErrs, validatePrivateDNSZoneName(networkSpec.PrivateDNSZoneName, controlPlaneEnabled, lbType, fldPath.Child("privateDNSZoneName"))...)
207+
allErrs = append(allErrs, validatePrivateDNSZoneResourceGroup(networkSpec.PrivateDNSZoneName, networkSpec.PrivateDNSZoneResourceGroup, fldPath.Child("privateDNSZoneResourceGroup"))...)
207208

208209
if len(allErrs) == 0 {
209210
return nil
@@ -589,6 +590,24 @@ func validatePrivateDNSZoneName(privateDNSZoneName string, controlPlaneEnabled b
589590
return allErrs
590591
}
591592

593+
// validatePrivateDNSZoneResourceGroup validates the PrivateDNSZoneResourceGroup.
594+
// A private DNS Zone's resource group is valid as long as privateDNSZoneName is provided with the private dns resource group name
595+
func validatePrivateDNSZoneResourceGroup(privateDNSZoneName string, privateDNSZoneResourceGroup string, fldPath *field.Path) field.ErrorList {
596+
var allErrs field.ErrorList
597+
598+
if privateDNSZoneResourceGroup != "" {
599+
if privateDNSZoneName == "" {
600+
allErrs = append(allErrs, field.Invalid(fldPath, privateDNSZoneName,
601+
"PrivateDNSZoneResourceGroup can only be used when PrivateDNSZoneName is provided"))
602+
}
603+
if err := validateResourceGroup(privateDNSZoneResourceGroup, fldPath); err != nil {
604+
allErrs = append(allErrs, err)
605+
}
606+
}
607+
608+
return allErrs
609+
}
610+
592611
// validateCloudProviderConfigOverrides validates CloudProviderConfigOverrides.
593612
func validateCloudProviderConfigOverrides(oldConfig, newConfig *CloudProviderConfigOverrides, fldPath *field.Path) field.ErrorList {
594613
var allErrs field.ErrorList

api/v1beta1/azurecluster_validation_test.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1371,6 +1371,81 @@ func TestPrivateDNSZoneName(t *testing.T) {
13711371
}
13721372
}
13731373

1374+
func TestPrivateDNSZoneResourceGroup(t *testing.T) {
1375+
testcases := []struct {
1376+
name string
1377+
network NetworkSpec
1378+
wantErr bool
1379+
expectedErr field.Error
1380+
}{
1381+
{
1382+
name: "testEmptyPrivateDNSZoneNameAndResourceGroup",
1383+
network: NetworkSpec{
1384+
NetworkClassSpec: NetworkClassSpec{
1385+
PrivateDNSZoneName: "",
1386+
PrivateDNSZoneResourceGroup: "",
1387+
},
1388+
},
1389+
wantErr: false,
1390+
},
1391+
{
1392+
name: "testValidPrivateDNSZoneNameAndResourceGroup",
1393+
network: NetworkSpec{
1394+
NetworkClassSpec: NetworkClassSpec{
1395+
PrivateDNSZoneName: "good.dns.io",
1396+
PrivateDNSZoneResourceGroup: "test-rg",
1397+
},
1398+
},
1399+
wantErr: false,
1400+
},
1401+
{
1402+
name: "testInvalidPrivateDNSZoneResourceGroup",
1403+
network: NetworkSpec{
1404+
NetworkClassSpec: NetworkClassSpec{
1405+
PrivateDNSZoneName: "good.dns.io",
1406+
PrivateDNSZoneResourceGroup: "inv@lid-rg",
1407+
},
1408+
},
1409+
expectedErr: field.Error{
1410+
Type: "FieldValueInvalid",
1411+
Field: "spec.networkSpec.privateDNSZoneResourceGroup",
1412+
BadValue: "inv@lid-rg",
1413+
Detail: "resourceGroup doesn't match regex ^[-\\w\\._\\(\\)]+$",
1414+
},
1415+
wantErr: true,
1416+
},
1417+
{
1418+
name: "testEmptyPrivateDNSZoneNameWithValidResourceGroup",
1419+
network: NetworkSpec{
1420+
NetworkClassSpec: NetworkClassSpec{
1421+
PrivateDNSZoneName: "",
1422+
PrivateDNSZoneResourceGroup: "test-rg",
1423+
},
1424+
},
1425+
expectedErr: field.Error{
1426+
Type: "FieldValueInvalid",
1427+
Field: "spec.networkSpec.privateDNSZoneResourceGroup",
1428+
BadValue: "",
1429+
Detail: "PrivateDNSZoneResourceGroup can only be used when PrivateDNSZoneName is provided",
1430+
},
1431+
wantErr: true,
1432+
},
1433+
}
1434+
1435+
for _, test := range testcases {
1436+
t.Run(test.name, func(t *testing.T) {
1437+
t.Parallel()
1438+
g := NewWithT(t)
1439+
err := validatePrivateDNSZoneResourceGroup(test.network.PrivateDNSZoneName, test.network.PrivateDNSZoneResourceGroup, field.NewPath("spec", "networkSpec", "privateDNSZoneResourceGroup"))
1440+
if test.wantErr {
1441+
g.Expect(err).To(ContainElement(MatchError(test.expectedErr.Error())))
1442+
} else {
1443+
g.Expect(err).To(BeEmpty())
1444+
}
1445+
})
1446+
}
1447+
}
1448+
13741449
func TestValidateNodeOutboundLB(t *testing.T) {
13751450
testcases := []struct {
13761451
name string

api/v1beta1/azurecluster_webhook.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,13 @@ func (c *AzureCluster) ValidateUpdate(oldRaw runtime.Object) (admission.Warnings
116116
allErrs = append(allErrs, err)
117117
}
118118

119+
if err := webhookutils.ValidateImmutable(
120+
field.NewPath("spec", "networkSpec", "privateDNSZoneResourceGroup"),
121+
old.Spec.NetworkSpec.PrivateDNSZoneResourceGroup,
122+
c.Spec.NetworkSpec.PrivateDNSZoneResourceGroup); err != nil {
123+
allErrs = append(allErrs, err)
124+
}
125+
119126
// Allow enabling azure bastion but avoid disabling it.
120127
if old.Spec.BastionSpec.AzureBastion != nil && !reflect.DeepEqual(old.Spec.BastionSpec.AzureBastion, c.Spec.BastionSpec.AzureBastion) {
121128
allErrs = append(allErrs,

api/v1beta1/azureclustertemplate_validation.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ func (c *AzureClusterTemplate) validateClusterTemplateSpec() field.ErrorList {
6262

6363
allErrs = append(allErrs, c.validatePrivateDNSZoneName()...)
6464

65+
allErrs = append(allErrs, c.validatePrivateDNSZoneResourceGroup()...)
66+
6567
return allErrs
6668
}
6769

@@ -169,3 +171,18 @@ func (c *AzureClusterTemplate) validatePrivateDNSZoneName() field.ErrorList {
169171

170172
return allErrs
171173
}
174+
175+
func (c *AzureClusterTemplate) validatePrivateDNSZoneResourceGroup() field.ErrorList {
176+
var allErrs field.ErrorList
177+
178+
fldPath := field.NewPath("spec").Child("template").Child("spec").Child("networkSpec").Child("privateDNSZoneResourceGroup")
179+
networkSpec := c.Spec.Template.Spec.NetworkSpec
180+
181+
allErrs = append(allErrs, validatePrivateDNSZoneResourceGroup(
182+
networkSpec.PrivateDNSZoneName,
183+
networkSpec.PrivateDNSZoneResourceGroup,
184+
fldPath,
185+
)...)
186+
187+
return allErrs
188+
}

api/v1beta1/azureclustertemplate_validation_test.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -822,6 +822,96 @@ func TestValidatePrivateDNSZoneName(t *testing.T) {
822822
})
823823
}
824824
}
825+
826+
func TestValidatePrivateDNSZoneResourceGroup(t *testing.T) {
827+
cases := []struct {
828+
name string
829+
clusterTemplate *AzureClusterTemplate
830+
expectValid bool
831+
expectedErr field.Error
832+
}{
833+
{
834+
name: "not set",
835+
clusterTemplate: &AzureClusterTemplate{
836+
ObjectMeta: metav1.ObjectMeta{
837+
Name: "test-cluster-template",
838+
},
839+
Spec: AzureClusterTemplateSpec{
840+
Template: AzureClusterTemplateResource{
841+
Spec: AzureClusterTemplateResourceSpec{
842+
NetworkSpec: NetworkTemplateSpec{},
843+
},
844+
},
845+
},
846+
},
847+
expectValid: true,
848+
},
849+
{
850+
name: "should be set if PrivateDNSZoneName is given",
851+
clusterTemplate: &AzureClusterTemplate{
852+
ObjectMeta: metav1.ObjectMeta{
853+
Name: "test-cluster-template",
854+
},
855+
Spec: AzureClusterTemplateSpec{
856+
Template: AzureClusterTemplateResource{
857+
Spec: AzureClusterTemplateResourceSpec{
858+
NetworkSpec: NetworkTemplateSpec{
859+
NetworkClassSpec: NetworkClassSpec{
860+
PrivateDNSZoneName: "e.f.g",
861+
PrivateDNSZoneResourceGroup: "a.b.c",
862+
},
863+
},
864+
},
865+
},
866+
},
867+
},
868+
expectValid: true,
869+
},
870+
{
871+
name: "should not be set if PrivateDNSZoneName is not given",
872+
clusterTemplate: &AzureClusterTemplate{
873+
ObjectMeta: metav1.ObjectMeta{
874+
Name: "test-cluster-template",
875+
},
876+
Spec: AzureClusterTemplateSpec{
877+
Template: AzureClusterTemplateResource{
878+
Spec: AzureClusterTemplateResourceSpec{
879+
NetworkSpec: NetworkTemplateSpec{
880+
NetworkClassSpec: NetworkClassSpec{
881+
PrivateDNSZoneResourceGroup: "a.b.c",
882+
},
883+
},
884+
},
885+
},
886+
},
887+
},
888+
expectValid: false,
889+
expectedErr: field.Error{
890+
Type: "FieldValueInvalid",
891+
Field: "spec.template.spec.networkSpec.privateDNSZoneResourceGroup",
892+
BadValue: "",
893+
Detail: "PrivateDNSZoneResourceGroup can only be used when PrivateDNSZoneName is provided",
894+
},
895+
},
896+
}
897+
898+
for _, c := range cases {
899+
tc := c
900+
t.Run(tc.name, func(t *testing.T) {
901+
t.Parallel()
902+
g := NewWithT(t)
903+
res := tc.clusterTemplate.validatePrivateDNSZoneResourceGroup()
904+
905+
if tc.expectValid {
906+
g.Expect(res).To(BeNil())
907+
} else {
908+
g.Expect(res).NotTo(BeNil())
909+
g.Expect(res).To(ContainElement(MatchError(tc.expectedErr.Error())))
910+
}
911+
})
912+
}
913+
}
914+
825915
func TestValidateNetworkSpec(t *testing.T) {
826916
cases := []struct {
827917
name string

api/v1beta1/types_class.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,11 @@ type NetworkClassSpec struct {
462462
// PrivateDNSZoneName defines the zone name for the Azure Private DNS.
463463
// +optional
464464
PrivateDNSZoneName string `json:"privateDNSZoneName,omitempty"`
465+
466+
// PrivateDNSZoneResourceGroup defines the resource group to be used for Azure Private DNS Zone.
467+
// If not specified, the resource group of the cluster will be used to create the Azure Private DNS Zone.
468+
// +optional
469+
PrivateDNSZoneResourceGroup string `json:"privateDNSZoneResourceGroup,omitempty"`
465470
}
466471

467472
// VnetClassSpec defines the VnetSpec properties that may be shared across several Azure clusters.

azure/scope/cluster.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -560,9 +560,13 @@ func (s *ClusterScope) VNetSpec() azure.ASOResourceSpecGetter[*asonetworkv1api20
560560
// PrivateDNSSpec returns the private dns zone spec.
561561
func (s *ClusterScope) PrivateDNSSpec() (zoneSpec azure.ResourceSpecGetter, linkSpec, recordSpec []azure.ResourceSpecGetter) {
562562
if s.IsAPIServerPrivate() {
563+
resourceGroup := s.ResourceGroup()
564+
if s.AzureCluster.Spec.NetworkSpec.PrivateDNSZoneResourceGroup != "" {
565+
resourceGroup = s.AzureCluster.Spec.NetworkSpec.PrivateDNSZoneResourceGroup
566+
}
563567
zone := privatedns.ZoneSpec{
564568
Name: s.GetPrivateDNSZoneName(),
565-
ResourceGroup: s.ResourceGroup(),
569+
ResourceGroup: resourceGroup,
566570
ClusterName: s.ClusterName(),
567571
AdditionalTags: s.AdditionalTags(),
568572
}
@@ -574,7 +578,7 @@ func (s *ClusterScope) PrivateDNSSpec() (zoneSpec azure.ResourceSpecGetter, link
574578
SubscriptionID: s.SubscriptionID(),
575579
VNetResourceGroup: s.Vnet().ResourceGroup,
576580
VNetName: s.Vnet().Name,
577-
ResourceGroup: s.ResourceGroup(),
581+
ResourceGroup: resourceGroup,
578582
ClusterName: s.ClusterName(),
579583
AdditionalTags: s.AdditionalTags(),
580584
}
@@ -585,7 +589,7 @@ func (s *ClusterScope) PrivateDNSSpec() (zoneSpec azure.ResourceSpecGetter, link
585589
SubscriptionID: s.SubscriptionID(),
586590
VNetResourceGroup: peering.ResourceGroup,
587591
VNetName: peering.RemoteVnetName,
588-
ResourceGroup: s.ResourceGroup(),
592+
ResourceGroup: resourceGroup,
589593
ClusterName: s.ClusterName(),
590594
AdditionalTags: s.AdditionalTags(),
591595
}
@@ -598,7 +602,7 @@ func (s *ClusterScope) PrivateDNSSpec() (zoneSpec azure.ResourceSpecGetter, link
598602
IP: s.APIServerPrivateIP(),
599603
},
600604
ZoneName: s.GetPrivateDNSZoneName(),
601-
ResourceGroup: s.ResourceGroup(),
605+
ResourceGroup: resourceGroup,
602606
}
603607

604608
return zone, links, records

config/crd/bases/infrastructure.cluster.x-k8s.io_azureclusters.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -927,6 +927,11 @@ spec:
927927
description: PrivateDNSZoneName defines the zone name for the
928928
Azure Private DNS.
929929
type: string
930+
privateDNSZoneResourceGroup:
931+
description: |-
932+
PrivateDNSZoneResourceGroup defines the resource group to be used for Azure Private DNS Zone.
933+
If not specified, the resource group of the cluster will be used to create the Azure Private DNS Zone.
934+
type: string
930935
subnets:
931936
description: Subnets is the configuration for the control-plane
932937
subnet and the node subnet.

config/crd/bases/infrastructure.cluster.x-k8s.io_azureclustertemplates.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,11 @@ spec:
594594
description: PrivateDNSZoneName defines the zone name
595595
for the Azure Private DNS.
596596
type: string
597+
privateDNSZoneResourceGroup:
598+
description: |-
599+
PrivateDNSZoneResourceGroup defines the resource group to be used for Azure Private DNS Zone.
600+
If not specified, the resource group of the cluster will be used to create the Azure Private DNS Zone.
601+
type: string
597602
subnets:
598603
description: Subnets is the configuration for the control-plane
599604
subnet and the node subnet.

0 commit comments

Comments
 (0)