Skip to content

Commit 5cc9de0

Browse files
committed
Managed daemons networking changes, to manage daemon-bridge network mode.
1 parent 44f8eb6 commit 5cc9de0

File tree

11 files changed

+577
-15
lines changed

11 files changed

+577
-15
lines changed

ecs-agent/netlib/common_test.go

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,10 @@ func getSingleNetNSAWSVPCTestData(testTaskID string) (*ecsacs.Task, tasknetworkc
7171
NetworkMode: types.NetworkModeAwsvpc,
7272
NetworkNamespaces: []*tasknetworkconfig.NetworkNamespace{
7373
{
74-
Name: netNSName,
75-
Path: netNSPath,
76-
Index: 0,
74+
Name: netNSName,
75+
Path: netNSPath,
76+
Index: 0,
77+
NetworkMode: types.NetworkModeAwsvpc,
7778
NetworkInterfaces: []*networkinterface.NetworkInterface{
7879
&netIfs[0],
7980
},
@@ -156,19 +157,21 @@ func getMultiNetNSMultiIfaceAWSVPCTestData(testTaskID string) (*ecsacs.Task, tas
156157
NetworkMode: types.NetworkModeAwsvpc,
157158
NetworkNamespaces: []*tasknetworkconfig.NetworkNamespace{
158159
{
159-
Name: primaryNetNSName,
160-
Path: primaryNetNSPath,
161-
Index: 0,
160+
Name: primaryNetNSName,
161+
Path: primaryNetNSPath,
162+
Index: 0,
163+
NetworkMode: types.NetworkModeAwsvpc,
162164
NetworkInterfaces: []*networkinterface.NetworkInterface{
163165
&netIfs[0],
164166
},
165167
KnownState: status.NetworkNone,
166168
DesiredState: status.NetworkReadyPull,
167169
},
168170
{
169-
Name: secondaryNetNSName,
170-
Path: secondaryNetNSPath,
171-
Index: 1,
171+
Name: secondaryNetNSName,
172+
Path: secondaryNetNSPath,
173+
Index: 1,
174+
NetworkMode: types.NetworkModeAwsvpc,
172175
NetworkInterfaces: []*networkinterface.NetworkInterface{
173176
&netIfs[1],
174177
},
@@ -323,6 +326,7 @@ func getV2NTestData(testTaskID string) (*ecsacs.Task, tasknetworkconfig.TaskNetw
323326
Name: netNSName,
324327
Path: netNSPath,
325328
Index: 0,
329+
NetworkMode: types.NetworkModeAwsvpc,
326330
NetworkInterfaces: netIfs,
327331
KnownState: status.NetworkNone,
328332
DesiredState: status.NetworkReadyPull,

ecs-agent/netlib/model/tasknetworkconfig/network_namespace.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/aws/amazon-ecs-agent/ecs-agent/netlib/model/networkinterface"
2323
"github.com/aws/amazon-ecs-agent/ecs-agent/netlib/model/serviceconnect"
2424
"github.com/aws/amazon-ecs-agent/ecs-agent/netlib/model/status"
25+
"github.com/aws/aws-sdk-go-v2/service/ecs/types"
2526
)
2627

2728
// NetworkNamespace is model representing each network namespace.
@@ -30,6 +31,10 @@ type NetworkNamespace struct {
3031
Path string
3132
Index int
3233

34+
// NetworkMode represents the network mode for this namespace.
35+
// Supported values: awsvpc (default), host(managed-instances only), daemon-bridge (managed-instances only).
36+
NetworkMode types.NetworkMode
37+
3338
// NetworkInterfaces represents ENIs or any kind of network interface associated the particular netns.
3439
NetworkInterfaces []*networkinterface.NetworkInterface
3540

@@ -58,6 +63,7 @@ func NewNetworkNamespace(
5863
NetworkInterfaces: networkInterfaces,
5964
KnownState: status.NetworkNone,
6065
DesiredState: status.NetworkReadyPull,
66+
NetworkMode: types.NetworkModeAwsvpc,
6167
}
6268

6369
// Sort interfaces as per their index values in ascending order.
@@ -104,3 +110,9 @@ func (ns *NetworkNamespace) GetInterfaceByIndex(idx int64) *networkinterface.Net
104110

105111
return nil
106112
}
113+
114+
// WithNetworkMode sets the NetworkMode field
115+
func (ns *NetworkNamespace) WithNetworkMode(mode types.NetworkMode) *NetworkNamespace {
116+
ns.NetworkMode = mode
117+
return ns
118+
}

ecs-agent/netlib/model/tasknetworkconfig/network_namespace_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package tasknetworkconfig
1919
import (
2020
"testing"
2121

22+
"github.com/aws/aws-sdk-go-v2/service/ecs/types"
2223
"github.com/stretchr/testify/assert"
2324
"github.com/stretchr/testify/require"
2425
)
@@ -47,6 +48,7 @@ func TestNewNetworkNamespace(t *testing.T) {
4748
assert.Equal(t, primaryNetNSName, netns.Name)
4849
assert.Equal(t, primaryNetNSPath, netns.Path)
4950
assert.Equal(t, 0, netns.Index)
51+
assert.Equal(t, types.NetworkModeAwsvpc, netns.NetworkMode)
5052
assert.Empty(t, netns.AppMeshConfig)
5153
assert.Equal(t, *netIFs[0], *netns.NetworkInterfaces[0])
5254
assert.Equal(t, *netIFs[1], *netns.NetworkInterfaces[1])
@@ -78,3 +80,41 @@ func TestNetworkNamespace_IsPrimary(t *testing.T) {
7880
require.Equal(t, tc.isPrimary, tc.netNS.IsPrimary())
7981
}
8082
}
83+
84+
func TestNetworkNamespace_WithNetworkMode(t *testing.T) {
85+
testCases := []struct {
86+
name string
87+
networkMode types.NetworkMode
88+
}{
89+
{
90+
name: "awsvpc mode",
91+
networkMode: types.NetworkModeAwsvpc,
92+
},
93+
{
94+
name: "host mode",
95+
networkMode: types.NetworkModeHost,
96+
},
97+
{
98+
name: "bridge mode",
99+
networkMode: types.NetworkModeBridge,
100+
},
101+
}
102+
103+
for _, tc := range testCases {
104+
t.Run(tc.name, func(t *testing.T) {
105+
netns := &NetworkNamespace{
106+
Name: "test-netns",
107+
Path: "/test/path",
108+
Index: 0,
109+
NetworkMode: types.NetworkModeAwsvpc, // default
110+
}
111+
112+
result := netns.WithNetworkMode(tc.networkMode)
113+
114+
// Verify the method returns the same instance
115+
assert.Same(t, netns, result)
116+
// Verify the NetworkMode was updated
117+
assert.Equal(t, tc.networkMode, netns.NetworkMode)
118+
})
119+
}
120+
}

ecs-agent/netlib/network_builder.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ func (nb *networkBuilder) Start(
102102
err = nb.startAWSVPC(ctx, taskID, netNS)
103103
case types.NetworkModeHost:
104104
err = nb.platformAPI.HandleHostMode()
105+
case "daemon-bridge":
106+
err = nb.platformAPI.ConfigureDaemonNetNS(netNS)
105107
default:
106108
err = errors.New("invalid network mode: " + string(mode))
107109
}
@@ -132,6 +134,8 @@ func (nb *networkBuilder) Stop(ctx context.Context, mode types.NetworkMode, task
132134
err = nb.stopAWSVPC(ctx, netNS)
133135
case types.NetworkModeHost:
134136
err = nb.platformAPI.HandleHostMode()
137+
case "daemon-bridge":
138+
err = nb.platformAPI.StopDaemonNetNS(ctx, netNS)
135139
default:
136140
err = errors.New("invalid network mode: " + string(mode))
137141
}

ecs-agent/netlib/network_builder_linux_test.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,13 @@ func TestNetworkBuilder_BuildTaskNetworkConfiguration(t *testing.T) {
7070

7171
func TestNetworkBuilder_Start(t *testing.T) {
7272
t.Run("awsvpc", testNetworkBuilder_StartAWSVPC)
73+
t.Run("daemon-bridge", testNetworkBuilder_StartDaemonBridge)
7374
}
7475

7576
// TestNetworkBuilder_Stop verifies stop workflow for AWSVPC mode.
7677
func TestNetworkBuilder_Stop(t *testing.T) {
7778
t.Run("awsvpc", testNetworkBuilder_StopAWSVPC)
79+
t.Run("daemon-bridge", testNetworkBuilder_StopDaemonBridge)
7880
}
7981

8082
// getTestFunc returns a test function that verifies the capability of the networkBuilder
@@ -380,3 +382,65 @@ func getExpectedCalls_StopAWSVPC(
380382
platformAPI.EXPECT().DeleteDNSConfig(netNS.Name).Return(nil).Times(1),
381383
platformAPI.EXPECT().DeleteNetNS(netNS.Path).Return(nil).Times(1))
382384
}
385+
386+
// testNetworkBuilder_StartDaemonBridge verifies that the expected platform API calls
387+
// are made by the network builder for daemon-bridge network mode.
388+
func testNetworkBuilder_StartDaemonBridge(t *testing.T) {
389+
ctrl := gomock.NewController(t)
390+
defer ctrl.Finish()
391+
392+
ctx := context.TODO()
393+
platformAPI := mock_platform.NewMockAPI(ctrl)
394+
metricsFactory := mock_metrics.NewMockEntryFactory(ctrl)
395+
mockEntry := mock_metrics.NewMockEntry(ctrl)
396+
netBuilder := &networkBuilder{
397+
platformAPI: platformAPI,
398+
metricsFactory: metricsFactory,
399+
}
400+
401+
netNS := &tasknetworkconfig.NetworkNamespace{
402+
Name: "daemon-test",
403+
Path: "/var/run/netns/daemon-test",
404+
}
405+
406+
gomock.InOrder(
407+
metricsFactory.EXPECT().New(metrics.BuildNetworkNamespaceMetricName).Return(mockEntry).Times(1),
408+
mockEntry.EXPECT().WithFields(gomock.Any()).Return(mockEntry).Times(1),
409+
platformAPI.EXPECT().ConfigureDaemonNetNS(netNS).Return(nil).Times(1),
410+
mockEntry.EXPECT().Done(nil).Times(1),
411+
)
412+
413+
err := netBuilder.Start(ctx, "daemon-bridge", taskID, netNS)
414+
require.NoError(t, err)
415+
}
416+
417+
// testNetworkBuilder_StopDaemonBridge verifies that the expected platform API calls
418+
// are made by the network builder for stopping daemon-bridge network mode.
419+
func testNetworkBuilder_StopDaemonBridge(t *testing.T) {
420+
ctrl := gomock.NewController(t)
421+
defer ctrl.Finish()
422+
423+
ctx := context.TODO()
424+
platformAPI := mock_platform.NewMockAPI(ctrl)
425+
metricsFactory := mock_metrics.NewMockEntryFactory(ctrl)
426+
mockEntry := mock_metrics.NewMockEntry(ctrl)
427+
netBuilder := &networkBuilder{
428+
platformAPI: platformAPI,
429+
metricsFactory: metricsFactory,
430+
}
431+
432+
netNS := &tasknetworkconfig.NetworkNamespace{
433+
Name: "daemon-test",
434+
Path: "/var/run/netns/daemon-test",
435+
}
436+
437+
gomock.InOrder(
438+
metricsFactory.EXPECT().New(metrics.DeleteNetworkNamespaceMetricName).Return(mockEntry).Times(1),
439+
mockEntry.EXPECT().WithFields(gomock.Any()).Return(mockEntry).Times(1),
440+
platformAPI.EXPECT().StopDaemonNetNS(ctx, netNS).Return(nil).Times(1),
441+
mockEntry.EXPECT().Done(nil).Times(1),
442+
)
443+
444+
err := netBuilder.Stop(ctx, "daemon-bridge", taskID, netNS)
445+
require.NoError(t, err)
446+
}

ecs-agent/netlib/platform/api.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,14 @@ type API interface {
7878
primaryIf *networkinterface.NetworkInterface,
7979
scConfig *serviceconnect.ServiceConnectConfig,
8080
) error
81+
82+
// ConfigureDaemonNetNS configures a network namespace for workloads running as daemons.
83+
// This is an internal networking mode available in EMI (ECS Managed Instances) only.
84+
ConfigureDaemonNetNS(netNS *tasknetworkconfig.NetworkNamespace) error
85+
86+
// StopDaemonNetNS stops and cleans up a daemon network namespace.
87+
// This is an internal networking mode available in EMI (ECS Managed Instances) only.
88+
StopDaemonNetNS(ctx context.Context, netNS *tasknetworkconfig.NetworkNamespace) error
8189
}
8290

8391
// Config contains platform-specific data.

ecs-agent/netlib/platform/common.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"time"
2020

2121
"github.com/aws/amazon-ecs-agent/ecs-agent/netlib/model/ecscni"
22+
"github.com/aws/amazon-ecs-agent/ecs-agent/netlib/model/tasknetworkconfig"
2223

2324
"github.com/containernetworking/cni/pkg/types"
2425
)
@@ -92,3 +93,15 @@ func (c *common) interfacesMACToName() (map[string]string, error) {
9293
func (c *common) HandleHostMode() error {
9394
return errors.New("invalid platform for host mode")
9495
}
96+
97+
// ConfigureDaemonNetNS configures a network namespace for workloads running as daemons.
98+
// This is an internal networking mode available in EMI (ECS Managed Instances) only.
99+
func (c *common) ConfigureDaemonNetNS(netNS *tasknetworkconfig.NetworkNamespace) error {
100+
return errors.New("daemon network namespaces are not supported in this platform")
101+
}
102+
103+
// StopDaemonNetNS stops and cleans up a daemon network namespace.
104+
// This is an internal networking mode available in EMI (ECS Managed Instances) only.
105+
func (c *common) StopDaemonNetNS(ctx context.Context, netNS *tasknetworkconfig.NetworkNamespace) error {
106+
return errors.New("daemon network namespaces are not supported in this platform")
107+
}

ecs-agent/netlib/platform/common_linux.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ func (c *common) buildAWSVPCNetworkNamespaces(
281281
return netNSs, nil
282282
}
283283

284-
// buildNetNS creates a single network namespace object using the input network config data.
284+
// buildNetNS creates a single awsvpc network namespace object using the input network config data.
285285
func (c *common) buildNetNS(
286286
taskID string,
287287
index int,

0 commit comments

Comments
 (0)