Skip to content

Commit

Permalink
add subnetName support to ammp
Browse files Browse the repository at this point in the history
  • Loading branch information
LochanRn committed Mar 19, 2023
1 parent 632516c commit 5d0169f
Show file tree
Hide file tree
Showing 14 changed files with 255 additions and 1 deletion.
1 change: 1 addition & 0 deletions api/v1alpha3/azuremanagedmachinepool_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ func (src *AzureManagedMachinePool) ConvertTo(dstRaw conversion.Hub) error {
if restored.Spec.KubeletConfig != nil {
dst.Spec.KubeletConfig = restored.Spec.KubeletConfig
}
dst.Spec.SubnetName = restored.Spec.SubnetName

dst.Status.LongRunningOperationStates = restored.Status.LongRunningOperationStates
dst.Status.Conditions = restored.Status.Conditions
Expand Down
1 change: 1 addition & 0 deletions api/v1alpha3/zz_generated.conversion.go

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

1 change: 1 addition & 0 deletions api/v1alpha4/azuremanagedmachinepool_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ func (src *AzureManagedMachinePool) ConvertTo(dstRaw conversion.Hub) error {
if restored.Spec.KubeletConfig != nil {
dst.Spec.KubeletConfig = restored.Spec.KubeletConfig
}
dst.Spec.SubnetName = restored.Spec.SubnetName

dst.Status.LongRunningOperationStates = restored.Status.LongRunningOperationStates
dst.Status.Conditions = restored.Status.Conditions
Expand Down
1 change: 1 addition & 0 deletions api/v1alpha4/zz_generated.conversion.go

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

3 changes: 3 additions & 0 deletions api/v1beta1/azuremanagedmachinepool_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,9 @@ type AzureManagedMachinePoolSpec struct {
// LinuxOSConfig specifies the custom Linux OS settings and configurations.
// +optional
LinuxOSConfig *LinuxOSConfig `json:"linuxOSConfig,omitempty"`
// SubnetName specifies the Subnet where the MachinePool will be placed
// +optional
SubnetName *string `json:"subnetName,omitempty"`
}

// ManagedMachinePoolScaling specifies scaling options.
Expand Down
19 changes: 19 additions & 0 deletions api/v1beta1/azuremanagedmachinepool_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ func (m *AzureManagedMachinePool) ValidateCreate(client client.Client) error {
m.validateEnableNodePublicIP,
m.validateKubeletConfig,
m.validateLinuxOSConfig,
m.validateSubnetName,
}

var errs []error
Expand Down Expand Up @@ -133,6 +134,13 @@ func (m *AzureManagedMachinePool) ValidateUpdate(oldRaw runtime.Object, client c
allErrs = append(allErrs, err)
}

if err := webhookutils.ValidateImmutable(
field.NewPath("Spec", "SubnetName"),
old.Spec.SubnetName,
m.Spec.SubnetName); err != nil {
allErrs = append(allErrs, err)
}

// custom headers are immutable
oldCustomHeaders := maps.FilterByKeyPrefix(old.ObjectMeta.Annotations, CustomHeaderPrefix)
newCustomHeaders := maps.FilterByKeyPrefix(m.ObjectMeta.Annotations, CustomHeaderPrefix)
Expand Down Expand Up @@ -356,6 +364,17 @@ func (m *AzureManagedMachinePool) validateEnableNodePublicIP() error {
return nil
}

func (m *AzureManagedMachinePool) validateSubnetName() error {
if m.Spec.SubnetName != nil {
subnetRegex := `^[-\w\._]+$`
if success, _ := regexp.Match(subnetRegex, []byte(*m.Spec.SubnetName)); !success {
return field.Invalid(field.NewPath("Spec", "SubnetName"), m.Spec.SubnetName,
fmt.Sprintf("name of subnet doesn't match regex %s", subnetRegex))
}
}
return nil
}

// validateKubeletConfig enforces the AKS API configuration for KubeletConfig.
// See: https://learn.microsoft.com/en-us/azure/aks/custom-node-configuration.
func (m *AzureManagedMachinePool) validateKubeletConfig() error {
Expand Down
48 changes: 48 additions & 0 deletions api/v1beta1/azuremanagedmachinepool_webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"testing"

"github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2022-03-01/containerservice"
"github.com/Azure/go-autorest/autorest/to"
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
Expand Down Expand Up @@ -535,6 +536,34 @@ func TestAzureManagedMachinePoolUpdatingWebhook(t *testing.T) {
},
wantErr: true,
},
{
name: "Can't update SubnetName with error",
new: &AzureManagedMachinePool{
Spec: AzureManagedMachinePoolSpec{
SubnetName: to.StringPtr("my-subnet"),
},
},
old: &AzureManagedMachinePool{
Spec: AzureManagedMachinePoolSpec{
SubnetName: to.StringPtr(""),
},
},
wantErr: true,
},
{
name: "Can't update SubnetName without error",
new: &AzureManagedMachinePool{
Spec: AzureManagedMachinePoolSpec{
SubnetName: to.StringPtr("my-subnet"),
},
},
old: &AzureManagedMachinePool{
Spec: AzureManagedMachinePoolSpec{
SubnetName: to.StringPtr("my-subnet"),
},
},
wantErr: false,
},
}
var client client.Client
for _, tc := range tests {
Expand Down Expand Up @@ -593,6 +622,25 @@ func TestAzureManagedMachinePool_ValidateCreate(t *testing.T) {
wantErr: true,
errorLen: 1,
},
{
name: "invalid subnetname",
ammp: &AzureManagedMachinePool{
Spec: AzureManagedMachinePoolSpec{
SubnetName: to.StringPtr("1+subnet"),
},
},
wantErr: true,
errorLen: 1,
},
{
name: "valid subnetname",
ammp: &AzureManagedMachinePool{
Spec: AzureManagedMachinePoolSpec{
SubnetName: to.StringPtr("my-subnet"),
},
},
wantErr: false,
},
{
name: "too few MaxPods",
ammp: &AzureManagedMachinePool{
Expand Down
5 changes: 5 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.

10 changes: 9 additions & 1 deletion azure/scope/managedmachinepool.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"fmt"
"strings"

"github.com/Azure/go-autorest/autorest/to"
"github.com/pkg/errors"
"k8s.io/utils/pointer"
infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1"
Expand Down Expand Up @@ -134,6 +135,13 @@ func (s *ManagedMachinePoolScope) Name() string {
return s.InfraMachinePool.Name
}

// SetSubnetName updates AzureManagedMachinePool.SubnetName if AzureManagedMachinePool.SubnetName is empty with s.ControlPlane.Spec.VirtualNetwork.Subnet.Name.
func (s *ManagedMachinePoolScope) SetSubnetName() {
if s.ControlPlane.Spec.VirtualNetwork.Name != "" && s.InfraMachinePool.Spec.SubnetName == nil {
s.InfraMachinePool.Spec.SubnetName = to.StringPtr(s.ControlPlane.Spec.VirtualNetwork.Subnet.Name)
}
}

// AgentPoolSpec returns an azure.ResourceSpecGetter for currently reconciled AzureManagedMachinePool.
func (s *ManagedMachinePoolScope) AgentPoolSpec() azure.ResourceSpecGetter {
return buildAgentPoolSpec(s.ControlPlane, s.MachinePool, s.InfraMachinePool, s.AgentPoolAnnotations())
Expand Down Expand Up @@ -166,7 +174,7 @@ func buildAgentPoolSpec(managedControlPlane *infrav1.AzureManagedControlPlane,
managedControlPlane.Spec.SubscriptionID,
managedControlPlane.Spec.VirtualNetwork.ResourceGroup,
managedControlPlane.Spec.VirtualNetwork.Name,
managedControlPlane.Spec.VirtualNetwork.Subnet.Name,
to.String(managedMachinePool.Spec.SubnetName),
),
Mode: managedMachinePool.Spec.Mode,
MaxPods: managedMachinePool.Spec.MaxPods,
Expand Down
148 changes: 148 additions & 0 deletions azure/scope/managedmachinepool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"testing"

"github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2022-03-01/containerservice"
"github.com/Azure/go-autorest/autorest/to"
"github.com/google/go-cmp/cmp"
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down Expand Up @@ -623,6 +624,147 @@ func TestManagedMachinePoolScope_OSDiskType(t *testing.T) {
}
}

func TestManagedMachinePoolScope_SubnetName(t *testing.T) {
scheme := runtime.NewScheme()
_ = expv1.AddToScheme(scheme)
_ = infrav1.AddToScheme(scheme)

cases := []struct {
Name string
Input ManagedMachinePoolScopeParams
Expected azure.ResourceSpecGetter
}{
{
Name: "Without Vnet and SubnetName",
Input: ManagedMachinePoolScopeParams{
Cluster: &clusterv1.Cluster{
ObjectMeta: metav1.ObjectMeta{
Name: "cluster1",
Namespace: "default",
},
},
ControlPlane: &infrav1.AzureManagedControlPlane{
ObjectMeta: metav1.ObjectMeta{
Name: "cluster1",
Namespace: "default",
},
Spec: infrav1.AzureManagedControlPlaneSpec{
SubscriptionID: "00000000-0000-0000-0000-000000000000",
},
},
ManagedMachinePool: ManagedMachinePool{
MachinePool: getMachinePool("pool0"),
InfraMachinePool: getAzureMachinePool("pool0", infrav1.NodePoolModeSystem),
},
},
Expected: &agentpools.AgentPoolSpec{
Name: "pool0",
SKU: "Standard_D2s_v3",
Replicas: 1,
Mode: "System",
Cluster: "cluster1",
VnetSubnetID: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups//providers/Microsoft.Network/virtualNetworks//subnets/",
Headers: map[string]string{},
},
},
{
Name: "With Vnet and Without SubnetName",
Input: ManagedMachinePoolScopeParams{
Cluster: &clusterv1.Cluster{
ObjectMeta: metav1.ObjectMeta{
Name: "cluster1",
Namespace: "default",
},
},
ControlPlane: &infrav1.AzureManagedControlPlane{
ObjectMeta: metav1.ObjectMeta{
Name: "cluster1",
Namespace: "default",
},
Spec: infrav1.AzureManagedControlPlaneSpec{
SubscriptionID: "00000000-0000-0000-0000-000000000000",
VirtualNetwork: infrav1.ManagedControlPlaneVirtualNetwork{
Name: "my-vnet",
Subnet: infrav1.ManagedControlPlaneSubnet{
Name: "my-vnet-subnet",
},
ResourceGroup: "my-resource-group",
},
},
},
ManagedMachinePool: ManagedMachinePool{
MachinePool: getMachinePool("pool1"),
InfraMachinePool: getAzureMachinePool("pool1", infrav1.NodePoolModeUser),
},
},
Expected: &agentpools.AgentPoolSpec{
Name: "pool1",
SKU: "Standard_D2s_v3",
Mode: "User",
Cluster: "cluster1",
Replicas: 1,
VnetSubnetID: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/my-resource-group/providers/Microsoft.Network/virtualNetworks/my-vnet/subnets/my-vnet-subnet",
Headers: map[string]string{},
},
},
{
Name: "With Vnet and With SubnetName",
Input: ManagedMachinePoolScopeParams{
Cluster: &clusterv1.Cluster{
ObjectMeta: metav1.ObjectMeta{
Name: "cluster1",
Namespace: "default",
},
},
ControlPlane: &infrav1.AzureManagedControlPlane{
ObjectMeta: metav1.ObjectMeta{
Name: "cluster1",
Namespace: "default",
},
Spec: infrav1.AzureManagedControlPlaneSpec{
SubscriptionID: "00000000-0000-0000-0000-000000000000",
VirtualNetwork: infrav1.ManagedControlPlaneVirtualNetwork{
Name: "my-vnet",
Subnet: infrav1.ManagedControlPlaneSubnet{
Name: "my-vnet-subnet",
},
ResourceGroup: "my-resource-group",
},
},
},
ManagedMachinePool: ManagedMachinePool{
MachinePool: getMachinePool("pool1"),
InfraMachinePool: getAzureMachinePoolWithSubnetName("pool1", to.StringPtr("my-subnet")),
},
},
Expected: &agentpools.AgentPoolSpec{
Name: "pool1",
SKU: "Standard_D2s_v3",
Mode: "User",
Cluster: "cluster1",
Replicas: 1,
VnetSubnetID: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/my-resource-group/providers/Microsoft.Network/virtualNetworks/my-vnet/subnets/my-subnet",
Headers: map[string]string{},
},
},
}

for _, c := range cases {
c := c
t.Run(c.Name, func(t *testing.T) {
g := NewWithT(t)
fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(c.Input.MachinePool, c.Input.InfraMachinePool, c.Input.ControlPlane).Build()
c.Input.Client = fakeClient
s, err := NewManagedMachinePoolScope(context.TODO(), c.Input)
g.Expect(err).To(Succeed())
agentPool := s.AgentPoolSpec()
if !reflect.DeepEqual(c.Expected, agentPool) {
t.Errorf("Got difference between expected result and result:\n%s", cmp.Diff(c.Expected, agentPool))
}
})
}
}

func TestManagedMachinePoolScope_KubeletDiskType(t *testing.T) {
scheme := runtime.NewScheme()
_ = expv1.AddToScheme(scheme)
Expand Down Expand Up @@ -763,6 +905,12 @@ func getAzureMachinePoolWithTaints(name string, taints infrav1.Taints) *infrav1.
return managedPool
}

func getAzureMachinePoolWithSubnetName(name string, subnetName *string) *infrav1.AzureManagedMachinePool {
managedPool := getAzureMachinePool(name, infrav1.NodePoolModeUser)
managedPool.Spec.SubnetName = subnetName
return managedPool
}

func getAzureMachinePoolWithOsDiskType(name string, osDiskType string) *infrav1.AzureManagedMachinePool {
managedPool := getAzureMachinePool(name, infrav1.NodePoolModeUser)
managedPool.Spec.OsDiskType = pointer.String(osDiskType)
Expand Down
1 change: 1 addition & 0 deletions azure/services/agentpools/agentpools.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ type AgentPoolScope interface {
SetCAPIMachinePoolReplicas(replicas *int32)
SetCAPIMachinePoolAnnotation(key, value string)
RemoveCAPIMachinePoolAnnotation(key string)
SetSubnetName()
}

// Service provides operations on Azure resources.
Expand Down
12 changes: 12 additions & 0 deletions azure/services/agentpools/mock_agentpools/agentpools_mock.go

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

Loading

0 comments on commit 5d0169f

Please sign in to comment.