Skip to content

Add unit tests for createHostNCApipaNetwork() function and apply changes from PR #3693 #3695

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

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
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
31 changes: 30 additions & 1 deletion cns/hnsclient/hnsclient_windows.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//go:build windows
// +build windows

package hnsclient

import (
Expand Down Expand Up @@ -53,6 +56,9 @@ const (
// Name of the loopback adapter needed to create Host NC apipa network
hostNCLoopbackAdapterName = "LoopbackAdapterHostNCConnectivity"

// Name of the loopback adapter created by HNS for Host NC apipa network
vEthernethostNCLoopbackAdapterName = "vEthernet (" + hostNCLoopbackAdapterName + ")"

// HNS rehydration issue requires this GW to be different than the loopback adapter ip, so we set it to .2
defaultHnsGwIPAddress = "169.254.128.2"
hnsLoopbackAdapterIPAddress = "169.254.128.1"
Expand Down Expand Up @@ -301,7 +307,12 @@ func createHostNCApipaNetwork(
}

// Create loopback adapter needed for this HNS network
if interfaceExists, _ := networkcontainers.InterfaceExists(hostNCLoopbackAdapterName); !interfaceExists {
// We need to first check the existence of either "LoopbackAdapterHostNCConnectivity" or the vEthernet(LoopbackAdapterHostNCConnectivity) interfaces
// If neither exists, we create the loopback adapter with the specified IP configuration.
shouldCreate, logMessage := shouldCreateLoopbackAdapter(networkcontainers.InterfaceExists)
logger.Printf(logMessage)

if shouldCreate {
ipconfig := cns.IPConfiguration{
IPSubnet: cns.IPSubnet{
IPAddress: hnsLoopbackAdapterIPAddress,
Expand Down Expand Up @@ -339,6 +350,24 @@ func createHostNCApipaNetwork(
return network, err
}

// shouldCreateLoopbackAdapter determines whether a loopback adapter should be created
// based on the existence of either the hostNCLoopbackAdapterName or vEthernethostNCLoopbackAdapterName interfaces
func shouldCreateLoopbackAdapter(
interfaceExistsFunc func(string) (bool, error)) (bool, string) {
loopbackInterfaceExists, _ := interfaceExistsFunc(hostNCLoopbackAdapterName)
vethernetLoopbackInterfaceExists, _ := interfaceExistsFunc(vEthernethostNCLoopbackAdapterName)

if loopbackInterfaceExists {
return false, hostNCLoopbackAdapterName + " already created, skipping loopback interface creation"
}
if vethernetLoopbackInterfaceExists {
return false, vEthernethostNCLoopbackAdapterName + " already created, skipping loopback interface creation"
}

// Neither interface exists, so we should create the loopback adapter
return true, "Creating loopback adapter"
}

// LogNetworkInterfaces logs the host's network interfaces in the default namespace.
func LogNetworkInterfaces() {
interfaces, err := net.Interfaces()
Expand Down
73 changes: 73 additions & 0 deletions cns/hnsclient/hnsclient_windows_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//go:build windows
// +build windows

package hnsclient

import (
Expand Down Expand Up @@ -33,3 +36,73 @@ func TestAdhocAdjustIPConfig(t *testing.T) {
})
}
}

func TestShouldCreateLoopbackAdapter(t *testing.T) {
tests := []struct {
name string
hostNCExists bool
vEthernetHostNCExists bool
expectedShouldCreate bool
expectedLogMessagePrefix string
}{
{
name: "should create when neither interface exists",
hostNCExists: false,
vEthernetHostNCExists: false,
expectedShouldCreate: true,
expectedLogMessagePrefix: "Creating loopback adapter",
},
{
name: "should not create when hostNCLoopbackAdapterName exists",
hostNCExists: true,
vEthernetHostNCExists: false,
expectedShouldCreate: false,
expectedLogMessagePrefix: "LoopbackAdapterHostNCConnectivity already created",
},
{
name: "should not create when vEthernethostNCLoopbackAdapterName exists",
hostNCExists: false,
vEthernetHostNCExists: true,
expectedShouldCreate: false,
expectedLogMessagePrefix: "vEthernet (LoopbackAdapterHostNCConnectivity) already created",
},
{
name: "should not create when both interfaces exist - prioritizes hostNCLoopbackAdapterName",
hostNCExists: true,
vEthernetHostNCExists: true,
expectedShouldCreate: false,
expectedLogMessagePrefix: "LoopbackAdapterHostNCConnectivity already created",
},
}

for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
// Create mock interface exists function
mockInterfaceExists := func(interfaceName string) (bool, error) {
switch interfaceName {
case hostNCLoopbackAdapterName:
return tt.hostNCExists, nil
case vEthernethostNCLoopbackAdapterName:
return tt.vEthernetHostNCExists, nil
default:
return false, nil
}
}

shouldCreate, logMessage := shouldCreateLoopbackAdapter(mockInterfaceExists)

assert.Equal(t, tt.expectedShouldCreate, shouldCreate)
assert.Contains(t, logMessage, tt.expectedLogMessagePrefix)
})
}
}

func TestConstants(t *testing.T) {
// Test that the vEthernet constant is constructed correctly
expectedVEthernetName := "vEthernet (LoopbackAdapterHostNCConnectivity)"
assert.Equal(t, expectedVEthernetName, vEthernethostNCLoopbackAdapterName)

// Test that the hostNCLoopbackAdapterName constant is as expected
assert.Equal(t, "LoopbackAdapterHostNCConnectivity", hostNCLoopbackAdapterName)
}