summaryrefslogtreecommitdiff
path: root/internal/network/network.go
diff options
context:
space:
mode:
authorJames O'Doherty <james@theodohertyfamily.com>2026-06-13 11:51:04 -0400
committerJames O'Doherty <james@theodohertyfamily.com>2026-06-13 11:51:04 -0400
commit29621ecbd1e77e6e1a70b6b3ea8fbe3a56e47df3 (patch)
treefa54976bbb0c4e9db59c983e7cb4e60c5119d18b /internal/network/network.go
parentf8afb7d5889f5c8b6ea256fd078fa8426d21c7be (diff)
refactor: implement dependency injection and enable parallel testing
This commit refactors the core system operations to use a manager-based dependency injection pattern, eliminating global state and resolving data races in the test suite. Architecture: - Introduced NetworkManager and NetworkOps interface in internal/network to abstract netlink calls. - Introduced MountOps and FileSystem interfaces in internal/namespace to abstract mount and filesystem operations. - Introduced TunnelManager in internal/wireguard to coordinate tunnel lifecycle using the new abstractions. - Updated internal/cli and internal/manager to use these managers. Testing: - Restored t.Parallel() to unit tests in internal/network and internal/wireguard. - Implemented setupParallelEnv and an enhanced mockFS in wireguard_unit_test.go to ensure complete test isolation. - Added bootstrap_test.go to verify launcher preparation logic in internal/namespace without requiring syscall.Exec. - Resolved data races in internal/network tests. CLI: - Added support for -h, --help, and -help flags for the main command. Verification: - Passed all tests (unit, integration, E2E). - Verified zero data races with 'go test -race'. - Passed golangci-lint and go vet.
Diffstat (limited to 'internal/network/network.go')
-rw-r--r--internal/network/network.go74
1 files changed, 65 insertions, 9 deletions
diff --git a/internal/network/network.go b/internal/network/network.go
index 6afcf5e..e9dce77 100644
--- a/internal/network/network.go
+++ b/internal/network/network.go
@@ -16,9 +16,54 @@ type InterfaceInfo struct {
Index int
}
+// NetworkOps abstracts the low-level netlink operations.
+type NetworkOps interface {
+ LinkList() ([]netlink.Link, error)
+ LinkByName(name string) (netlink.Link, error)
+ LinkSetMTU(link netlink.Link, mtu int) error
+ LinkSetUp(link netlink.Link) error
+ AddrAdd(link netlink.Link, addr *netlink.Addr) error
+ RouteAdd(route *netlink.Route) error
+ RouteReplace(route *netlink.Route) error
+}
+
+// realNetworkOps is the production implementation using netlink.
+type realNetworkOps struct{}
+
+func (r *realNetworkOps) LinkList() ([]netlink.Link, error) { return netlink.LinkList() }
+func (r *realNetworkOps) LinkByName(name string) (netlink.Link, error) {
+ return netlink.LinkByName(name)
+}
+func (r *realNetworkOps) LinkSetMTU(link netlink.Link, mtu int) error {
+ return netlink.LinkSetMTU(link, mtu)
+}
+func (r *realNetworkOps) LinkSetUp(link netlink.Link) error { return netlink.LinkSetUp(link) }
+func (r *realNetworkOps) AddrAdd(link netlink.Link, addr *netlink.Addr) error {
+ return netlink.AddrAdd(link, addr)
+}
+
+func (r *realNetworkOps) RouteAdd(route *netlink.Route) error { return netlink.RouteAdd(route) }
+func (r *realNetworkOps) RouteReplace(route *netlink.Route) error { return netlink.RouteReplace(route) }
+
+// DefaultNetworkOps is the global instance used by the package functions.
+// It can be replaced during tests.
+var DefaultNetworkOps NetworkOps = &realNetworkOps{}
+
+// NetworkManager coordinates network configuration within a namespace.
+type NetworkManager struct {
+ Ops NetworkOps
+}
+
+// NewNetworkManager creates a new NetworkManager with production defaults.
+func NewNetworkManager() *NetworkManager {
+ return &NetworkManager{
+ Ops: DefaultNetworkOps,
+ }
+}
+
// ListInterfaces returns a list of all network interfaces present in the current namespace.
-func ListInterfaces() ([]InterfaceInfo, error) {
- links, err := netlink.LinkList()
+func (nm *NetworkManager) ListInterfaces() ([]InterfaceInfo, error) {
+ links, err := nm.Ops.LinkList()
if err != nil {
return nil, fmt.Errorf("failed to list interfaces: %w", err)
}
@@ -35,17 +80,17 @@ func ListInterfaces() ([]InterfaceInfo, error) {
// ConfigureInterface sets the MTU, brings the interface up, assigns an IP address,
// and configures the default route.
-func ConfigureInterface(name, address string, mtu int) error {
- link, err := netlink.LinkByName(name)
+func (nm *NetworkManager) ConfigureInterface(name, address string, mtu int) error {
+ link, err := nm.Ops.LinkByName(name)
if err != nil {
return fmt.Errorf("failed to find link %s: %w", name, err)
}
- if err := netlink.LinkSetMTU(link, mtu); err != nil {
+ if err := nm.Ops.LinkSetMTU(link, mtu); err != nil {
return fmt.Errorf("failed to set MTU %d on link %s: %w", mtu, name, err)
}
- if err := netlink.LinkSetUp(link); err != nil {
+ if err := nm.Ops.LinkSetUp(link); err != nil {
return fmt.Errorf("failed to bring up link %s: %w", name, err)
}
@@ -53,7 +98,7 @@ func ConfigureInterface(name, address string, mtu int) error {
if err != nil {
return fmt.Errorf("invalid IP address %s: %w", address, err)
}
- if err := netlink.AddrAdd(link, addr); err != nil {
+ if err := nm.Ops.AddrAdd(link, addr); err != nil {
if !strings.Contains(err.Error(), "file exists") {
return fmt.Errorf("failed to add address %s to link %s: %w", address, name, err)
}
@@ -72,11 +117,22 @@ func ConfigureInterface(name, address string, mtu int) error {
Dst: dst,
}
- if err := netlink.RouteAdd(route); err != nil {
- if err := netlink.RouteReplace(route); err != nil {
+ if err := nm.Ops.RouteAdd(route); err != nil {
+ if err := nm.Ops.RouteReplace(route); err != nil {
return fmt.Errorf("failed to configure default route via %s: %w", name, err)
}
}
return nil
}
+
+// ListInterfaces returns a list of all network interfaces present in the current namespace.
+func ListInterfaces() ([]InterfaceInfo, error) {
+ return NewNetworkManager().ListInterfaces()
+}
+
+// ConfigureInterface sets the MTU, brings the interface up, assigns an IP address,
+// and configures the default route.
+func ConfigureInterface(name, address string, mtu int) error {
+ return NewNetworkManager().ConfigureInterface(name, address, mtu)
+}