diff --git a/ecs-agent/netlib/model/status/network_status.go b/ecs-agent/netlib/model/status/network_status.go new file mode 100644 index 00000000000..b6fdb9d2d84 --- /dev/null +++ b/ecs-agent/netlib/model/status/network_status.go @@ -0,0 +1,42 @@ +package status + +// NetworkStatus represents the status of a network resource. +type NetworkStatus string + +const ( + // NetworkNone is the initial status of the ENI. + NetworkNone NetworkStatus = "NONE" + // NetworkReadyPull indicates that the ENI is ready for downloading resources associated with + // the execution role. This includes container images, task secrets and configs. + NetworkReadyPull NetworkStatus = "READY_PULL" + // NetworkReady indicates that the ENI is ready for use by containers in the task. + NetworkReady NetworkStatus = "READY" + // NetworkDeleted indicates that the ENI is deleted. + NetworkDeleted NetworkStatus = "DELETED" +) + +var ( + eniStatusOrder = map[NetworkStatus]int{ + NetworkNone: 0, + NetworkReadyPull: 1, + NetworkReady: 2, + NetworkDeleted: 3, + } +) + +func (es NetworkStatus) String() string { + return string(es) +} + +func (es NetworkStatus) ENIStatusBackwards(es2 NetworkStatus) bool { + return eniStatusOrder[es] < eniStatusOrder[es2] +} + +func GetAllENIStatuses() []NetworkStatus { + return []NetworkStatus{ + NetworkNone, + NetworkReadyPull, + NetworkReady, + NetworkDeleted, + } +} diff --git a/ecs-agent/netlib/model/status/network_status_test.go b/ecs-agent/netlib/model/status/network_status_test.go new file mode 100644 index 00000000000..27131e0b46b --- /dev/null +++ b/ecs-agent/netlib/model/status/network_status_test.go @@ -0,0 +1,52 @@ +//go:build unit +// +build unit + +package status + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +// TestNetworkStatus verifies the corresponding string values of each status +// is appropriate. +func TestNetworkStatus(t *testing.T) { + testCases := []struct { + status NetworkStatus + str string + }{ + { + status: NetworkNone, + str: "NONE", + }, + { + status: NetworkReadyPull, + str: "READY_PULL", + }, + { + status: NetworkReady, + str: "READY", + }, + { + status: NetworkDeleted, + str: "DELETED", + }, + } + for _, tc := range testCases { + t.Run(tc.str, func(t *testing.T) { + assert.Equal(t, tc.str, (&tc.status).String()) + }) + } +} + +// TestNetworkStatusOrder verifies that order of statuses are as required. +func TestNetworkStatusOrder(t *testing.T) { + assert.True(t, NetworkNone.ENIStatusBackwards(NetworkReadyPull)) + assert.True(t, NetworkReadyPull.ENIStatusBackwards(NetworkReady)) + assert.True(t, NetworkReady.ENIStatusBackwards(NetworkDeleted)) + + assert.False(t, NetworkReadyPull.ENIStatusBackwards(NetworkNone)) + assert.False(t, NetworkReady.ENIStatusBackwards(NetworkReadyPull)) + assert.False(t, NetworkDeleted.ENIStatusBackwards(NetworkReady)) +} diff --git a/ecs-agent/netlib/model/tasknetworkconfig/common_test.go b/ecs-agent/netlib/model/tasknetworkconfig/common_test.go new file mode 100644 index 00000000000..35da4a995fc --- /dev/null +++ b/ecs-agent/netlib/model/tasknetworkconfig/common_test.go @@ -0,0 +1,44 @@ +package tasknetworkconfig + +import ni "github.com/aws/amazon-ecs-agent/ecs-agent/netlib/model/networkinterface" + +const ( + primaryNetNSName = "primary-netns" + secondaryNetNSName = "secondary-netns" + primaryInterfaceName = "primary-interface" + secondaryInterfaceName = "secondary-interface" +) + +func getTestTaskNetworkConfig() *TaskNetworkConfig { + return &TaskNetworkConfig{ + NetworkNamespaces: getTestNetworkNamespaces(), + } +} + +func getTestNetworkNamespaces() []*NetworkNamespace { + return []*NetworkNamespace{ + { + Name: secondaryNetNSName, + Index: 1, + NetworkInterfaces: getTestNetworkInterfaces(), + }, + { + Name: primaryNetNSName, + Index: 0, + NetworkInterfaces: getTestNetworkInterfaces(), + }, + } +} + +func getTestNetworkInterfaces() []*ni.NetworkInterface { + return []*ni.NetworkInterface{ + { + Name: secondaryInterfaceName, + Index: 1, + }, + { + Name: primaryInterfaceName, + Index: 0, + }, + } +} diff --git a/ecs-agent/netlib/model/tasknetworkconfig/network_namespace.go b/ecs-agent/netlib/model/tasknetworkconfig/network_namespace.go new file mode 100644 index 00000000000..ae6d9103e43 --- /dev/null +++ b/ecs-agent/netlib/model/tasknetworkconfig/network_namespace.go @@ -0,0 +1,35 @@ +package tasknetworkconfig + +import ( + "github.com/aws/amazon-ecs-agent/ecs-agent/netlib/model/appmesh" + "github.com/aws/amazon-ecs-agent/ecs-agent/netlib/model/networkinterface" +) + +// NetworkNamespace is model representing each network namespace. +type NetworkNamespace struct { + Name string + Path string + Index int + + // NetworkInterfaces represents ENIs or any kind of network interface associated the particular netns. + NetworkInterfaces []*networkinterface.NetworkInterface + + // AppMeshConfig holds AppMesh related parameters for the particular netns. + AppMeshConfig *appmesh.AppMesh + + // TODO: Add Service Connect model here once it is moved under the netlib package. + + KnownState string + DesiredState string +} + +// GetPrimaryInterface returns the network interface that has the index value of 0 within +// the network namespace. +func (ns NetworkNamespace) GetPrimaryInterface() *networkinterface.NetworkInterface { + for _, ni := range ns.NetworkInterfaces { + if ni.Index == 0 { + return ni + } + } + return nil +} diff --git a/ecs-agent/netlib/model/tasknetworkconfig/network_namespace_test.go b/ecs-agent/netlib/model/tasknetworkconfig/network_namespace_test.go new file mode 100644 index 00000000000..6af1b838658 --- /dev/null +++ b/ecs-agent/netlib/model/tasknetworkconfig/network_namespace_test.go @@ -0,0 +1,31 @@ +//go:build unit +// +build unit + +package tasknetworkconfig + +import ( + "github.com/aws/amazon-ecs-agent/ecs-agent/netlib/model/networkinterface" + + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNetworkNamespace_GetPrimaryInterface(t *testing.T) { + netns := &NetworkNamespace{ + NetworkInterfaces: []*networkinterface.NetworkInterface{ + { + Index: 1, + Name: secondaryInterfaceName, + }, + { + Index: 0, + Name: primaryInterfaceName, + }, + }, + } + assert.Equal(t, primaryInterfaceName, netns.GetPrimaryInterface().Name) + + netns = &NetworkNamespace{} + assert.Empty(t, netns.GetPrimaryInterface()) +} diff --git a/ecs-agent/netlib/model/tasknetworkconfig/task_network_config.go b/ecs-agent/netlib/model/tasknetworkconfig/task_network_config.go new file mode 100644 index 00000000000..61ce6c0ddfb --- /dev/null +++ b/ecs-agent/netlib/model/tasknetworkconfig/task_network_config.go @@ -0,0 +1,29 @@ +package tasknetworkconfig + +import ni "github.com/aws/amazon-ecs-agent/ecs-agent/netlib/model/networkinterface" + +// TaskNetworkConfig is the top level network data structure associated with a task. +type TaskNetworkConfig struct { + NetworkNamespaces []*NetworkNamespace + NetworkMode string +} + +// GetPrimaryInterface returns the interface with index 0 inside the network namespace +// with index 0 associated with the task's network config. +func (tnc *TaskNetworkConfig) GetPrimaryInterface() *ni.NetworkInterface { + if tnc != nil && tnc.GetPrimaryNetNS() != nil { + return tnc.GetPrimaryNetNS().GetPrimaryInterface() + } + return nil +} + +// GetPrimaryNetNS returns the netns with index 0 associated with the task's network config. +func (tnc *TaskNetworkConfig) GetPrimaryNetNS() *NetworkNamespace { + for _, netns := range tnc.NetworkNamespaces { + if netns.Index == 0 { + return netns + } + } + + return nil +} diff --git a/ecs-agent/netlib/model/tasknetworkconfig/task_network_config_test.go b/ecs-agent/netlib/model/tasknetworkconfig/task_network_config_test.go new file mode 100644 index 00000000000..1e2716df339 --- /dev/null +++ b/ecs-agent/netlib/model/tasknetworkconfig/task_network_config_test.go @@ -0,0 +1,28 @@ +//go:build unit +// +build unit + +package tasknetworkconfig + +import ( + "github.com/stretchr/testify/assert" + + "testing" +) + +func TestTaskNetworkConfig_GetPrimaryInterface(t *testing.T) { + testNetConfig := getTestTaskNetworkConfig() + assert.Equal(t, primaryInterfaceName, testNetConfig.GetPrimaryInterface().Name) + + testNetConfig = &TaskNetworkConfig{ + NetworkNamespaces: []*NetworkNamespace{}, + } + assert.Nil(t, testNetConfig.GetPrimaryInterface()) +} + +func TestTaskNetworkConfig_GetPrimaryNetNS(t *testing.T) { + testNetConfig := getTestTaskNetworkConfig() + assert.Equal(t, primaryNetNSName, testNetConfig.GetPrimaryNetNS().Name) + + testNetConfig = &TaskNetworkConfig{} + assert.Nil(t, testNetConfig.GetPrimaryNetNS()) +}