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

[improvement] : simplify addr calculation and fetch instance config only for vlans #551

Merged
merged 3 commits into from
Oct 25, 2024
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
37 changes: 21 additions & 16 deletions controller/linodemachine_controller_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,12 +170,6 @@
return nil, fmt.Errorf("get instance ips: %w", err)
}

// get the default instance config
configs, err := machineScope.LinodeClient.ListInstanceConfigs(ctx, instanceID, &linodego.ListOptions{})
if err != nil || len(configs) == 0 {
return nil, fmt.Errorf("list instance configs: %w", err)
}

ips := []clusterv1.MachineAddress{}
// check if a node has public ipv4 ip and store it
if len(addresses.IPv4.Public) == 0 {
Expand All @@ -198,21 +192,32 @@
Type: clusterv1.MachineExternalIP,
})

// Iterate over interfaces in config and find VPC or VLAN specific ips
for _, iface := range configs[0].Interfaces {
if iface.VPCID != nil && iface.IPv4.VPC != "" {
// check if a node has vpc specific ip and store it
for _, vpcIP := range addresses.IPv4.VPC {
if *vpcIP.Address != "" {
ips = append(ips, clusterv1.MachineAddress{
Address: iface.IPv4.VPC,
Address: *vpcIP.Address,
Type: clusterv1.MachineInternalIP,
})
}
}

if iface.Purpose == linodego.InterfacePurposeVLAN {
// vlan addresses have a /11 appended to them - we should strip it out.
ips = append(ips, clusterv1.MachineAddress{
Address: netip.MustParsePrefix(iface.IPAMAddress).Addr().String(),
Type: clusterv1.MachineInternalIP,
})
if machineScope.LinodeCluster.Spec.Network.UseVlan {
// get the default instance config
configs, err := machineScope.LinodeClient.ListInstanceConfigs(ctx, instanceID, &linodego.ListOptions{})
if err != nil || len(configs) == 0 {
return nil, fmt.Errorf("list instance configs: %w", err)
}

Check warning on line 210 in controller/linodemachine_controller_helpers.go

View check run for this annotation

Codecov / codecov/patch

controller/linodemachine_controller_helpers.go#L209-L210

Added lines #L209 - L210 were not covered by tests

// Iterate over interfaces in config and find VLAN specific ips
for _, iface := range configs[0].Interfaces {
if iface.Purpose == linodego.InterfacePurposeVLAN {
// vlan addresses have a /11 appended to them - we should strip it out.
ips = append(ips, clusterv1.MachineAddress{
Address: netip.MustParsePrefix(iface.IPAMAddress).Addr().String(),
Type: clusterv1.MachineInternalIP,
})
}
}
}

Expand Down
221 changes: 172 additions & 49 deletions controller/linodemachine_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ var _ = Describe("create", Label("machine", "create"), func() {
BootInstance(ctx, 123, 0).
After(createInst).
Return(nil)
getAddrs := mockLinodeClient.EXPECT().
mockLinodeClient.EXPECT().
GetInstanceIPAddresses(ctx, 123).
After(bootInst).
Return(&linodego.InstanceIPAddressResponse{
Expand All @@ -243,14 +243,6 @@ var _ = Describe("create", Label("machine", "create"), func() {
},
},
}, nil)
mockLinodeClient.EXPECT().
ListInstanceConfigs(ctx, 123, gomock.Any()).
After(getAddrs).
Return([]linodego.InstanceConfig{{
Devices: &linodego.InstanceConfigDeviceMap{
SDA: &linodego.InstanceConfigDevice{DiskID: 100},
},
}}, nil)
linodeMachine.Spec.FirewallRef = &corev1.ObjectReference{Name: "fw2", Namespace: defaultNamespace, Kind: "LinodeFirewall", APIVersion: "infrastructure.cluster.x-k8s.io/v1alpha2"}
mScope := scope.MachineScope{
Client: k8sClient,
Expand Down Expand Up @@ -295,7 +287,7 @@ var _ = Describe("create", Label("machine", "create"), func() {
BootInstance(ctx, 123, 0).
After(createInst).
Return(nil)
getAddrs := mockLinodeClient.EXPECT().
mockLinodeClient.EXPECT().
GetInstanceIPAddresses(ctx, 123).
After(bootInst).
Return(&linodego.InstanceIPAddressResponse{
Expand All @@ -309,14 +301,6 @@ var _ = Describe("create", Label("machine", "create"), func() {
},
},
}, nil)
mockLinodeClient.EXPECT().
ListInstanceConfigs(ctx, 123, gomock.Any()).
After(getAddrs).
Return([]linodego.InstanceConfig{{
Devices: &linodego.InstanceConfigDeviceMap{
SDA: &linodego.InstanceConfigDevice{DiskID: 100},
},
}}, nil)

mScope := scope.MachineScope{
Client: k8sClient,
Expand Down Expand Up @@ -536,7 +520,7 @@ var _ = Describe("create", Label("machine", "create"), func() {
}).
After(getAddrs).MaxTimes(2).
Return(nil, nil)
getAddrs = mockLinodeClient.EXPECT().
mockLinodeClient.EXPECT().
GetInstanceIPAddresses(ctx, 123).
After(createNB).
Return(&linodego.InstanceIPAddressResponse{
Expand All @@ -550,14 +534,6 @@ var _ = Describe("create", Label("machine", "create"), func() {
},
},
}, nil).MaxTimes(2)
mockLinodeClient.EXPECT().
ListInstanceConfigs(ctx, 123, gomock.Any()).
After(getAddrs).
Return([]linodego.InstanceConfig{{
Devices: &linodego.InstanceConfigDeviceMap{
SDA: &linodego.InstanceConfigDevice{DiskID: 100},
},
}}, nil)

mScope := scope.MachineScope{
Client: k8sClient,
Expand Down Expand Up @@ -716,6 +692,7 @@ var _ = Describe("create", Label("machine", "create"), func() {
IPv4: &linodego.InstanceIPv4Response{
Private: []*linodego.InstanceIP{{Address: "192.168.0.2"}},
Public: []*linodego.InstanceIP{{Address: "172.0.0.2"}},
VPC: []*linodego.VPCIP{{Address: ptr.To("10.0.0.2")}},
},
IPv6: &linodego.InstanceIPv6Response{
SLAAC: &linodego.InstanceIP{
Expand All @@ -731,32 +708,21 @@ var _ = Describe("create", Label("machine", "create"), func() {
}).
After(getAddrs).
Return(nil, nil).MaxTimes(2)
getAddrs = mockLinodeClient.EXPECT().
mockLinodeClient.EXPECT().
GetInstanceIPAddresses(ctx, 123).
After(createNB).
Return(&linodego.InstanceIPAddressResponse{
IPv4: &linodego.InstanceIPv4Response{
Private: []*linodego.InstanceIP{{Address: "192.168.0.2"}},
Public: []*linodego.InstanceIP{{Address: "172.0.0.2"}},
VPC: []*linodego.VPCIP{{Address: ptr.To("10.0.0.2")}},
},
IPv6: &linodego.InstanceIPv6Response{
SLAAC: &linodego.InstanceIP{
Address: "fd00::",
},
},
}, nil).MaxTimes(2)
mockLinodeClient.EXPECT().
ListInstanceConfigs(ctx, 123, gomock.Any()).
After(getAddrs).
Return([]linodego.InstanceConfig{{
Devices: &linodego.InstanceConfigDeviceMap{
SDA: &linodego.InstanceConfigDevice{DiskID: 100},
},
Interfaces: []linodego.InstanceConfigInterface{{
VPCID: ptr.To(1),
IPv4: &linodego.VPCIPv4{VPC: "10.0.0.2"},
}},
}}, nil)

_, err = reconciler.reconcileCreate(ctx, logger, &mScope)
Expect(err).NotTo(HaveOccurred())
Expand Down Expand Up @@ -889,7 +855,7 @@ var _ = Describe("createDNS", Label("machine", "createDNS"), func() {
BootInstance(ctx, 123, 0).
After(createInst).
Return(nil)
getAddrs := mockLinodeClient.EXPECT().
mockLinodeClient.EXPECT().
GetInstanceIPAddresses(ctx, 123).
After(bootInst).
Return(&linodego.InstanceIPAddressResponse{
Expand All @@ -903,14 +869,6 @@ var _ = Describe("createDNS", Label("machine", "createDNS"), func() {
},
},
}, nil)
mockLinodeClient.EXPECT().
ListInstanceConfigs(ctx, 123, gomock.Any()).
After(getAddrs).
Return([]linodego.InstanceConfig{{
Devices: &linodego.InstanceConfigDeviceMap{
SDA: &linodego.InstanceConfigDevice{DiskID: 100},
},
}}, nil)

mScope := scope.MachineScope{
Client: k8sClient,
Expand Down Expand Up @@ -1975,3 +1933,168 @@ var _ = Describe("machine in VPC", Label("machine", "VPC"), Ordered, func() {
}}))
})
})

var _ = Describe("machine in vlan", Label("machine", "vlan"), Ordered, func() {
var machine clusterv1.Machine
var secret corev1.Secret

var mockCtrl *gomock.Controller
var testLogs *bytes.Buffer
var logger logr.Logger

var reconciler *LinodeMachineReconciler
var linodeMachine infrav1alpha2.LinodeMachine

cluster := clusterv1.Cluster{
ObjectMeta: metav1.ObjectMeta{
Name: "mock",
Namespace: defaultNamespace,
},
}

linodeCluster := infrav1alpha2.LinodeCluster{
Spec: infrav1alpha2.LinodeClusterSpec{
Region: "us-ord",
Network: infrav1alpha2.NetworkSpec{
UseVlan: true,
},
},
}

recorder := record.NewFakeRecorder(10)

BeforeEach(func(ctx SpecContext) {
secret = corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "bootstrap-secret",
Namespace: defaultNamespace,
},
Data: map[string][]byte{
"value": []byte("userdata"),
},
}
Expect(k8sClient.Create(ctx, &secret)).To(Succeed())

machine = clusterv1.Machine{
ObjectMeta: metav1.ObjectMeta{
Namespace: defaultNamespace,
Labels: make(map[string]string),
},
Spec: clusterv1.MachineSpec{
Bootstrap: clusterv1.Bootstrap{
DataSecretName: ptr.To("bootstrap-secret"),
},
},
}

linodeMachine = infrav1alpha2.LinodeMachine{
ObjectMeta: metav1.ObjectMeta{
Name: "mock",
Namespace: defaultNamespace,
UID: "12345",
},
Spec: infrav1alpha2.LinodeMachineSpec{
Type: "g6-nanode-1",
Image: rutil.DefaultMachineControllerLinodeImage,
DiskEncryption: string(linodego.InstanceDiskEncryptionEnabled),
},
}

mockCtrl = gomock.NewController(GinkgoT())
testLogs = &bytes.Buffer{}
logger = zap.New(
zap.WriteTo(GinkgoWriter),
zap.WriteTo(testLogs),
zap.UseDevMode(true),
)
reconciler = &LinodeMachineReconciler{
Recorder: recorder,
}
})

AfterEach(func(ctx SpecContext) {
Expect(k8sClient.Delete(ctx, &secret)).To(Succeed())

mockCtrl.Finish()
for len(recorder.Events) > 0 {
<-recorder.Events
}
})

It("creates an instance with vlan", func(ctx SpecContext) {
mockLinodeClient := mock.NewMockLinodeClient(mockCtrl)
getRegion := mockLinodeClient.EXPECT().
GetRegion(ctx, gomock.Any()).
Return(&linodego.Region{Capabilities: []string{linodego.CapabilityMetadata, linodego.CapabilityDiskEncryption}}, nil)
getImage := mockLinodeClient.EXPECT().
GetImage(ctx, gomock.Any()).
After(getRegion).
Return(&linodego.Image{Capabilities: []string{"cloud-init"}}, nil)
createInst := mockLinodeClient.EXPECT().
CreateInstance(ctx, gomock.Any()).
After(getImage).
Return(&linodego.Instance{
ID: 123,
IPv4: []*net.IP{ptr.To(net.IPv4(192, 168, 0, 2))},
IPv6: "fd00::",
Status: linodego.InstanceOffline,
}, nil)
mockLinodeClient.EXPECT().
OnAfterResponse(gomock.Any()).
Return()
bootInst := mockLinodeClient.EXPECT().
BootInstance(ctx, 123, 0).
After(createInst).
Return(nil)
getAddrs := mockLinodeClient.EXPECT().
GetInstanceIPAddresses(ctx, 123).
After(bootInst).
Return(&linodego.InstanceIPAddressResponse{
IPv4: &linodego.InstanceIPv4Response{
Private: []*linodego.InstanceIP{{Address: "192.168.0.2"}},
Public: []*linodego.InstanceIP{{Address: "172.0.0.2"}},
VPC: []*linodego.VPCIP{},
},
IPv6: &linodego.InstanceIPv6Response{
SLAAC: &linodego.InstanceIP{
Address: "fd00::",
},
},
}, nil)
mockLinodeClient.EXPECT().
ListInstanceConfigs(ctx, 123, gomock.Any()).
After(getAddrs).
Return([]linodego.InstanceConfig{{
Interfaces: []linodego.InstanceConfigInterface{
{
Purpose: linodego.InterfacePurposeVLAN,
IPAMAddress: "10.0.0.2/11",
},
},
}}, nil)

mScope := scope.MachineScope{
Client: k8sClient,
LinodeClient: mockLinodeClient,
Cluster: &cluster,
Machine: &machine,
LinodeCluster: &linodeCluster,
LinodeMachine: &linodeMachine,
}

patchHelper, err := patch.NewHelper(mScope.LinodeMachine, k8sClient)
Expect(err).NotTo(HaveOccurred())
mScope.PatchHelper = patchHelper

_, err = reconciler.reconcileCreate(ctx, logger, &mScope)
Expect(err).NotTo(HaveOccurred())
_, err = reconciler.reconcileCreate(ctx, logger, &mScope)
Expect(err).NotTo(HaveOccurred())

Expect(rutil.ConditionTrue(&linodeMachine, ConditionPreflightMetadataSupportConfigured)).To(BeTrue())
Expect(rutil.ConditionTrue(&linodeMachine, ConditionPreflightCreated)).To(BeTrue())
Expect(rutil.ConditionTrue(&linodeMachine, ConditionPreflightConfigured)).To(BeTrue())
Expect(rutil.ConditionTrue(&linodeMachine, ConditionPreflightBootTriggered)).To(BeTrue())
Expect(rutil.ConditionTrue(&linodeMachine, ConditionPreflightReady)).To(BeTrue())
})
})
Loading