Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable public MEC on CAPZ #2836

Merged
merged 1 commit into from
Mar 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ create-aks-cluster: $(KUSTOMIZE) $(ENVSUBST) $(KUBECTL) ## Create a aks cluster.
create-cluster: ## Create a workload development Kubernetes cluster on Azure in a kind management cluster.
EXP_CLUSTER_RESOURCE_SET=true \
EXP_MACHINE_POOL=true \
EXP_EDGEZONE=true \
$(MAKE) create-management-cluster \
create-workload-cluster

Expand Down Expand Up @@ -712,7 +713,7 @@ kind-create: $(KUBECTL) ## Create capz kind cluster if needed.

.PHONY: tilt-up
tilt-up: install-tools kind-create ## Start tilt and build kind cluster if needed.
CLUSTER_TOPOLOGY=true EXP_CLUSTER_RESOURCE_SET=true EXP_MACHINE_POOL=true EXP_KUBEADM_BOOTSTRAP_FORMAT_IGNITION=true tilt up
CLUSTER_TOPOLOGY=true EXP_CLUSTER_RESOURCE_SET=true EXP_MACHINE_POOL=true EXP_KUBEADM_BOOTSTRAP_FORMAT_IGNITION=true EXP_EDGEZONE=true tilt up

.PHONY: delete-cluster
delete-cluster: delete-workload-cluster ## Deletes the example kind cluster "capz".
Expand Down
3 changes: 3 additions & 0 deletions api/v1alpha3/azurecluster_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ func (src *AzureCluster) ConvertTo(dstRaw conversion.Hub) error {
// Restore list of virtual network peerings
dst.Spec.NetworkSpec.Vnet.Peerings = restored.Spec.NetworkSpec.Vnet.Peerings

// Restore ExtendedLocation properties
dst.Spec.ExtendedLocation = restored.Spec.ExtendedLocation

return nil
}

Expand Down
3 changes: 3 additions & 0 deletions api/v1alpha4/azurecluster_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ func (src *AzureCluster) ConvertTo(dstRaw conversion.Hub) error {
// Restore list of virtual network peerings
dst.Spec.NetworkSpec.Vnet.Peerings = restored.Spec.NetworkSpec.Vnet.Peerings

// Restore ExtendedLocation properties
dst.Spec.ExtendedLocation = restored.Spec.ExtendedLocation

// Restore API Server LB IP tags.
for _, restoredFrontendIP := range restored.Spec.NetworkSpec.APIServerLB.FrontendIPs {
for i, dstFrontendIP := range dst.Spec.NetworkSpec.APIServerLB.FrontendIPs {
Expand Down
6 changes: 6 additions & 0 deletions api/v1beta1/azurecluster_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/utils/pointer"
"sigs.k8s.io/cluster-api-provider-azure/feature"
)

const (
Expand Down Expand Up @@ -96,6 +97,11 @@ func (c *AzureCluster) validateClusterSpec(old *AzureCluster) field.ErrorList {
allErrs = append(allErrs, validateCloudProviderConfigOverrides(c.Spec.CloudProviderConfigOverrides, oldCloudProviderConfigOverrides,
field.NewPath("spec").Child("cloudProviderConfigOverrides"))...)

// If ClusterSpec has non-nil ExtendedLocation field but not enable EdgeZone feature gate flag, ClusterSpec validation failed.
if !feature.Gates.Enabled(feature.EdgeZone) && c.Spec.ExtendedLocation != nil {
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "ExtendedLocation"), "can be set only if the EdgeZone feature flag is enabled"))
}

if err := validateBastionSpec(c.Spec.BastionSpec, field.NewPath("spec").Child("azureBastion").Child("bastionSpec")); err != nil {
allErrs = append(allErrs, err)
}
Expand Down
24 changes: 24 additions & 0 deletions api/v1beta1/azurecluster_validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1505,3 +1505,27 @@ func TestServiceEndpointsLackRequiredFieldLocations(t *testing.T) {
g.Expect(errs[0].Error()).To(ContainSubstring("locations are required for all service endpoints"))
})
}

func TestClusterWithExtendedLocationInvalid(t *testing.T) {
g := NewWithT(t)

type test struct {
name string
cluster *AzureCluster
}

testCase := test{
name: "azurecluster spec with extended location but not enable EdgeZone feature gate flag",
cluster: createValidCluster(),
}

testCase.cluster.Spec.ExtendedLocation = &ExtendedLocationSpec{
Name: "rr4",
Type: "EdgeZone",
}

t.Run(testCase.name, func(t *testing.T) {
err := testCase.cluster.validateClusterSpec(nil)
g.Expect(err).NotTo(BeNil())
})
}
12 changes: 12 additions & 0 deletions api/v1beta1/azurecluster_webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,18 @@ func TestAzureCluster_ValidateCreate(t *testing.T) {
}(),
wantErr: true,
},
{
name: "azurecluster with ExtendedLocation and false EdgeZone feature flag",
cluster: func() *AzureCluster {
cluster := createValidCluster()
cluster.Spec.ExtendedLocation = &ExtendedLocationSpec{
Name: "rr4",
Type: "EdgeZone",
}
return cluster
}(),
wantErr: true,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
Expand Down
14 changes: 14 additions & 0 deletions api/v1beta1/types_class.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ type AzureClusterClassSpec struct {

Location string `json:"location"`

// ExtendedLocation is an optional set of ExtendedLocation properties for clusters on Azure public MEC.
// +optional
ExtendedLocation *ExtendedLocationSpec `json:"extendedLocation,omitempty"`
upxinxin marked this conversation as resolved.
Show resolved Hide resolved

// AdditionalTags is an optional set of tags to add to Azure resources managed by the Azure provider, in addition to the
// ones added by default.
// +optional
Expand Down Expand Up @@ -52,6 +56,16 @@ type AzureClusterClassSpec struct {
CloudProviderConfigOverrides *CloudProviderConfigOverrides `json:"cloudProviderConfigOverrides,omitempty"`
}

// ExtendedLocationSpec defines the ExtendedLocation properties to enable CAPZ for Azure public MEC.
type ExtendedLocationSpec struct {
// Name defines the name for the extended location.
Name string `json:"name"`

// Type defines the type for the extended location.
// +kubebuilder:validation:Enum=EdgeZone
Type string `json:"type"`
}

// NetworkClassSpec defines the NetworkSpec properties that may be shared across several Azure clusters.
type NetworkClassSpec struct {
// PrivateDNSZoneName defines the zone name for the Azure Private DNS.
Expand Down
20 changes: 20 additions & 0 deletions api/v1beta1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

46 changes: 46 additions & 0 deletions azure/converters/extendedlocation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
Copyright 2023 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package converters

import (
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2021-11-01/compute"
"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-08-01/network"
"github.com/Azure/go-autorest/autorest/to"
infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1"
)

// ExtendedLocationToNetworkSDK converts infrav1.ExtendedLocationSpec to network.ExtendedLocation.
func ExtendedLocationToNetworkSDK(src *infrav1.ExtendedLocationSpec) *network.ExtendedLocation {
if src == nil {
return nil
}
return &network.ExtendedLocation{
Name: to.StringPtr(src.Name),
Type: network.ExtendedLocationTypes(src.Type),
}
}

// ExtendedLocationToComputeSDK converts infrav1.ExtendedLocationSpec to compute.ExtendedLocation.
func ExtendedLocationToComputeSDK(src *infrav1.ExtendedLocationSpec) *compute.ExtendedLocation {
if src == nil {
return nil
}
return &compute.ExtendedLocation{
Name: to.StringPtr(src.Name),
Type: compute.ExtendedLocationTypes(src.Type),
}
}
upxinxin marked this conversation as resolved.
Show resolved Hide resolved
91 changes: 91 additions & 0 deletions azure/converters/extendedlocation_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
Copyright 2023 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package converters

import (
"reflect"
"testing"

"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2021-11-01/compute"
"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-08-01/network"
"github.com/Azure/go-autorest/autorest/to"
infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1"
)

func TestExtendedLocationToNetworkSDK(t *testing.T) {
tests := []struct {
name string
args *infrav1.ExtendedLocationSpec
want *network.ExtendedLocation
}{
{
name: "normal extendedLocation instance",
args: &infrav1.ExtendedLocationSpec{
Name: "value",
Type: "Edge",
},
want: &network.ExtendedLocation{
Name: to.StringPtr("value"),
Type: network.ExtendedLocationTypes("Edge"),
},
},
{
name: "nil extendedLocation properties",
args: nil,
want: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := ExtendedLocationToNetworkSDK(tt.args); !reflect.DeepEqual(got, tt.want) {
t.Errorf("ExtendedLocationToNetworkSDK() = %v, want %v", got, tt.want)
}
})
}
}

func TestExtendedLocationToComputeSDK(t *testing.T) {
tests := []struct {
name string
args *infrav1.ExtendedLocationSpec
want *compute.ExtendedLocation
}{
{
name: "normal extendedLocation instance",
args: &infrav1.ExtendedLocationSpec{
Name: "value",
Type: "Edge",
},
want: &compute.ExtendedLocation{
Name: to.StringPtr("value"),
Type: compute.ExtendedLocationTypes("Edge"),
},
},
{
name: "nil extendedLocation properties",
args: nil,
want: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := ExtendedLocationToComputeSDK(tt.args); !reflect.DeepEqual(got, tt.want) {
t.Errorf("ExtendedLocationToComputeSDK() = %v, want %v", got, tt.want)
}
})
}
}
3 changes: 3 additions & 0 deletions azure/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ type ClusterDescriber interface {
ResourceGroup() string
ClusterName() string
Location() string
ExtendedLocation() *infrav1.ExtendedLocationSpec
ExtendedLocationName() string
ExtendedLocationType() string
AdditionalTags() infrav1.Tags
AvailabilitySetEnabled() bool
CloudProviderConfigOverrides() *infrav1.CloudProviderConfigOverrides
Expand Down
Loading