diff --git a/agent/app/agent.go b/agent/app/agent.go index 1736be7686b..2a658d96673 100644 --- a/agent/app/agent.go +++ b/agent/app/agent.go @@ -297,6 +297,7 @@ func (agent *ecsAgent) doStart(containerChangeEventStream *eventstream.EventStre if agent.cfg.ContainerMetadataEnabled { agent.metadataManager.SetContainerInstanceARN(agent.containerInstanceARN) agent.metadataManager.SetAvailabilityZone(agent.availabilityZone) + agent.metadataManager.SetHostPrivateIPv4Address(agent.getHostPrivateIPv4AddressFromEC2Metadata()) agent.metadataManager.SetHostPublicIPv4Address(agent.getHostPublicIPv4AddressFromEC2Metadata()) } @@ -695,10 +696,22 @@ func mergeTags(localTags []*ecs.Tag, ec2Tags []*ecs.Tag) []*ecs.Tag { return utils.MapToTags(tagsMap) } +// getHostPrivateIPv4AddressFromEC2Metadata will retrieve the PrivateIPAddress (IPv4) of this +// instance throught the EC2 API +func (agent *ecsAgent) getHostPrivateIPv4AddressFromEC2Metadata() string { + // Get instance private IP from ec2 metadata client. + hostPrivateIPv4Address, err := agent.ec2MetadataClient.PrivateIPv4Address() + if err != nil { + seelog.Errorf("Unable to retrieve Host Instance PrivateIPv4 Address: %v", err) + return "" + } + return hostPrivateIPv4Address +} + // getHostPublicIPv4AddressFromEC2Metadata will retrieve the PublicIPAddress (IPv4) of this // instance through the EC2 API func (agent *ecsAgent) getHostPublicIPv4AddressFromEC2Metadata() string { - // Get instance ID from ec2 metadata client. + // Get instance public IP from ec2 metadata client. hostPublicIPv4Address, err := agent.ec2MetadataClient.PublicIPv4Address() if err != nil { seelog.Errorf("Unable to retrieve Host Instance PublicIPv4 Address: %v", err) diff --git a/agent/app/agent_test.go b/agent/app/agent_test.go index 043c5485771..0471db607f0 100644 --- a/agent/app/agent_test.go +++ b/agent/app/agent_test.go @@ -51,10 +51,11 @@ import ( ) const ( - clusterName = "some-cluster" - containerInstanceARN = "container-instance1" - availabilityZone = "us-west-2b" - hostPublicIPv4Address = "127.0.0.1" + clusterName = "some-cluster" + containerInstanceARN = "container-instance1" + availabilityZone = "us-west-2b" + hostPrivateIPv4Address = "127.0.0.1" + hostPublicIPv4Address = "127.0.0.1" ) var apiVersions = []dockerclient.DockerVersion{ @@ -304,6 +305,7 @@ func TestDoStartRegisterAvailabilityZone(t *testing.T) { defer ctrl.Finish() ec2MetadataClient := mock_ec2.NewMockEC2MetadataClient(ctrl) + ec2MetadataClient.EXPECT().PrivateIPv4Address().Return(hostPrivateIPv4Address, nil) ec2MetadataClient.EXPECT().PublicIPv4Address().Return(hostPublicIPv4Address, nil) var discoverEndpointsInvoked sync.WaitGroup @@ -339,6 +341,7 @@ func TestDoStartRegisterAvailabilityZone(t *testing.T) { "arn:123", availabilityZone, nil), containermetadata.EXPECT().SetContainerInstanceARN("arn:123"), containermetadata.EXPECT().SetAvailabilityZone(availabilityZone), + containermetadata.EXPECT().SetHostPrivateIPv4Address(hostPrivateIPv4Address), containermetadata.EXPECT().SetHostPublicIPv4Address(hostPublicIPv4Address), imageManager.EXPECT().SetSaver(gomock.Any()), dockerClient.EXPECT().ContainerEvents(gomock.Any()), @@ -1115,6 +1118,38 @@ func TestGetContainerInstanceTagsFromEC2APIFailToDescribeECSTagsForInstance(t *t assert.Nil(t, resTags) } +func TestGetHostPrivateIPv4AddressFromEC2Metadata(t *testing.T) { + ctrl := gomock.NetController(t) + defer ctrl.Finish() + + ec2MetadataClient := mock_ec2.NewMockEC2MetadataClient(ctrl) + ec2Client := mock_ec2.NewMockClient(ctrl) + + agent := &ecsAgent{ + ec2MetadataClient: ec2MetadataClient, + ec2Client: ec2Client, + } + ec2MetadataClient.EXPECT().PrivateIPv4Address().Return(hostPrivateIPv4Address, nil) + + assert.Equal(t, hostPrivateIPv4Address, agent.getHostPrivateIPv4AddressFromEC2Metadata()) +} + +func TestGetHostPrivateIPv4AddressFromEC2MetadataFailWithError(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + ec2MetadataClient := mock_ec2.NewMockEC2MetadataClient(ctrl) + ec2Client := mock_ec2.NewMockClient(ctrl) + + agent := &ecsAgent{ + ec2MetadataClient: ec2MetadataClient, + ec2Client: ec2Client, + } + ec2MetadataClient.EXPECT().PrivateIPv4Address().Return("", errors.New("Unable to get IP Address")) + + assert.Empty(t, agent.getHostPrivateIPv4AddressFromEC2Metadata()) +} + func TestGetHostPublicIPv4AddressFromEC2Metadata(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() diff --git a/agent/containermetadata/manager.go b/agent/containermetadata/manager.go index a61710cc3b3..4d102c09715 100644 --- a/agent/containermetadata/manager.go +++ b/agent/containermetadata/manager.go @@ -40,6 +40,7 @@ const ( type Manager interface { SetContainerInstanceARN(string) SetAvailabilityZone(string) + SetHostPrivateIPv4Address(string) SetHostPublicIPv4Address(string) Create(*dockercontainer.Config, *dockercontainer.HostConfig, *apitask.Task, string) error Update(context.Context, string, *apitask.Task, string) error @@ -67,7 +68,9 @@ type metadataManager struct { ioutilWrap ioutilwrapper.IOUtil // availabilityZone is the availabiltyZone where task is in availabilityZone string - // hostPublicIPv4Address is the public IPv4 address associated with the EC2 instance ID + // hostPrivateIPv4Address is the private IPv4 address associated with the EC2 instance + hostPrivateIPv4Address string + // hostPublicIPv4Address is the public IPv4 address associated with the EC2 instance hostPublicIPv4Address string } @@ -95,6 +98,12 @@ func (manager *metadataManager) SetAvailabilityZone(availabilityZone string) { manager.availabilityZone = availabilityZone } +// SetHostPrivateIPv4Address sets the metadataManager's hostPrivateIPv4Address which is not available +// at its creation as this information is not present immediately at the agent's startup +func (manager *metadataManager) SetHostPrivateIPv4Address(ipv4address string) { + manager.hostPrivateIPv4Address = ipv4address +} + // SetHostPublicIPv4Address sets the metadataManager's hostPublicIPv4Address which is not available // at its creation as this information is not present immediately at the agent's startup func (manager *metadataManager) SetHostPublicIPv4Address(ipv4address string) { diff --git a/agent/containermetadata/manager_test.go b/agent/containermetadata/manager_test.go index 61396fe8912..42f678cdafb 100644 --- a/agent/containermetadata/manager_test.go +++ b/agent/containermetadata/manager_test.go @@ -41,6 +41,7 @@ const ( containerName = "container" dataDir = "ecs_mockdata" availabilityZone = "us-west-2b" + hostPrivateIPv4Address = "127.0.0.1" hostPublicIPv4Address = "127.0.0.1" ) @@ -75,6 +76,15 @@ func TestSetAvailabilityZone(t *testing.T) { assert.Equal(t, mockAvailabilityZone, newManager.availabilityZone) } +// TestSetHostPrivateIPv4Address checks whether the container hostPublicIPv4Address is set correctly. +func TestSetHostPrivateIPv4Address(t *testing.T) { + _, _, _, _, done := managerSetup(t) + defer done() + newManager := &metadataManager{} + newManager.SetHostPrivateIPv4Address(hostPublicIPv4Address) + assert.Equal(t, hostPrivateIPv4Address, newManager.hostPrivateIPv4Address) +} + // TestSetHostPublicIPv4Address checks whether the container hostPublicIPv4Address is set correctly. func TestSetHostPublicIPv4Address(t *testing.T) { _, _, _, _, done := managerSetup(t) diff --git a/agent/containermetadata/mocks/containermetadata_mocks.go b/agent/containermetadata/mocks/containermetadata_mocks.go index 8a97bd9ab87..7a9421c2609 100644 --- a/agent/containermetadata/mocks/containermetadata_mocks.go +++ b/agent/containermetadata/mocks/containermetadata_mocks.go @@ -95,6 +95,16 @@ func (mr *MockManagerMockRecorder) SetContainerInstanceARN(arg0 interface{}) *go return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetContainerInstanceARN", reflect.TypeOf((*MockManager)(nil).SetContainerInstanceARN), arg0) } +// SetHostPrivateIPv4Address mocks base method +func (m *MockManager) SetHostPrivateIPv4Address(arg0 string) { + m.ctrl.Call(m, "SetHostPrivateIPv4Address", arg0) +} + +// SetHostPrivateIPv4Address indicates an expected call of SetHostPrivateIPv4Address +func (mr *MockManagerMockRecorder) SetHostPrivateIPv4Address(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetHostPrivateIPv4Address", reflect.TypeOf((*MockManager)(nil).SetHostPublicIPv4Address), arg0) +} + // SetHostPublicIPv4Address mocks base method func (m *MockManager) SetHostPublicIPv4Address(arg0 string) { m.ctrl.Call(m, "SetHostPublicIPv4Address", arg0) diff --git a/agent/containermetadata/parse_metadata.go b/agent/containermetadata/parse_metadata.go index 3ffd05cdb58..546439b012f 100644 --- a/agent/containermetadata/parse_metadata.go +++ b/agent/containermetadata/parse_metadata.go @@ -38,10 +38,11 @@ func (manager *metadataManager) parseMetadataAtContainerCreate(task *apitask.Tas taskDefinitionFamily: task.Family, taskDefinitionRevision: task.Version, }, - containerInstanceARN: manager.containerInstanceARN, - metadataStatus: MetadataInitial, - availabilityZone: manager.availabilityZone, - hostPublicIPv4Address: manager.hostPublicIPv4Address, + containerInstanceARN: manager.containerInstanceARN, + metadataStatus: MetadataInitial, + availabilityZone: manager.availabilityZone, + hostPrivateIPv4Address: manager.hostPrivateIPv4Address, + hostPublicIPv4Address: manager.hostPublicIPv4Address, } } @@ -63,6 +64,7 @@ func (manager *metadataManager) parseMetadata(dockerContainer *types.ContainerJS containerInstanceARN: manager.containerInstanceARN, metadataStatus: MetadataReady, availabilityZone: manager.availabilityZone, + hostPrivateIPv4Address: manager.hostPrivateIPv4Address, hostPublicIPv4Address: manager.hostPublicIPv4Address, } } diff --git a/agent/containermetadata/parse_metadata_test.go b/agent/containermetadata/parse_metadata_test.go index 6617078bef5..db0306afbbe 100644 --- a/agent/containermetadata/parse_metadata_test.go +++ b/agent/containermetadata/parse_metadata_test.go @@ -41,15 +41,17 @@ func TestParseContainerCreate(t *testing.T) { mockCluster := cluster mockContainerInstanceARN := containerInstanceARN mockAvailabilityZone := availabilityZone + mockHostPrivateIPv4Address := hostPrivateIPv4Address mockHostPublicIPv4Address := hostPublicIPv4Address expectedStatus := string(MetadataInitial) newManager := &metadataManager{ - cluster: mockCluster, - containerInstanceARN: mockContainerInstanceARN, - availabilityZone: mockAvailabilityZone, - hostPublicIPv4Address: mockHostPublicIPv4Address, + cluster: mockCluster, + containerInstanceARN: mockContainerInstanceARN, + availabilityZone: mockAvailabilityZone, + hostPrivateIPv4Address: mockHostPrivateIPv4Address, + hostPublicIPv4Address: mockHostPublicIPv4Address, } metadata := newManager.parseMetadataAtContainerCreate(mockTask, mockContainerName) @@ -58,6 +60,7 @@ func TestParseContainerCreate(t *testing.T) { assert.Equal(t, metadata.taskMetadata.taskARN, mockTaskARN, "Expected task ARN "+mockTaskARN) assert.Equal(t, metadata.containerInstanceARN, mockContainerInstanceARN, "Expected container instance ARN "+mockContainerInstanceARN) assert.Equal(t, metadata.availabilityZone, mockAvailabilityZone, "Expected availabilityZone "+mockAvailabilityZone) + assert.Equal(t, metadata.hostPrivateIPv4Address, mockHostPrivateIPv4Address, "Expected hostPrivateIPv4Address "+hostPrivateIPv4Address) assert.Equal(t, metadata.hostPublicIPv4Address, mockHostPublicIPv4Address, "Expected hostPublicIPv4Address "+hostPublicIPv4Address) assert.Equal(t, metadata.taskMetadata.taskDefinitionFamily, mockTaskDefinitionFamily, "Expected task definition family "+mockTaskDefinitionFamily) assert.Equal(t, metadata.taskMetadata.taskDefinitionRevision, mockTaskDefinitionRevision, "Expected task definition revision "+mockTaskDefinitionRevision) @@ -71,15 +74,17 @@ func TestParseHasNoContainer(t *testing.T) { mockCluster := cluster mockContainerInstanceARN := containerInstanceARN mockAvailabilityZone := availabilityZone + mockHostPrivateIPv4Address := hostPrivateIPv4Address mockHostPublicIPv4Address := hostPublicIPv4Address expectedStatus := string(MetadataReady) newManager := &metadataManager{ - cluster: mockCluster, - containerInstanceARN: mockContainerInstanceARN, - availabilityZone: mockAvailabilityZone, - hostPublicIPv4Address: mockHostPublicIPv4Address, + cluster: mockCluster, + containerInstanceARN: mockContainerInstanceARN, + availabilityZone: mockAvailabilityZone, + hostPrivateIPv4Address: mockHostPrivateIPv4Address, + hostPublicIPv4Address: mockHostPublicIPv4Address, } metadata := newManager.parseMetadata(nil, mockTask, mockContainerName) @@ -88,6 +93,7 @@ func TestParseHasNoContainer(t *testing.T) { assert.Equal(t, metadata.taskMetadata.taskARN, mockTaskARN, "Expected task ARN "+mockTaskARN) assert.Equal(t, metadata.containerInstanceARN, mockContainerInstanceARN, "Expected container instance ARN "+mockContainerInstanceARN) assert.Equal(t, metadata.availabilityZone, mockAvailabilityZone, "Expected availabilityZone "+mockAvailabilityZone) + assert.Equal(t, metadata.hostPrivateIPv4Address, mockHostPrivateIPv4Address, "Expected hostPrivateIPv4Address "+hostPrivateIPv4Address) assert.Equal(t, metadata.hostPublicIPv4Address, mockHostPublicIPv4Address, "Expected hostPublicIPv4Address "+hostPublicIPv4Address) assert.Equal(t, string(metadata.metadataStatus), expectedStatus, "Expected status "+expectedStatus) assert.Equal(t, metadata.dockerContainerMetadata.containerID, "", "Expected empty container metadata") @@ -103,6 +109,7 @@ func TestParseHasConfig(t *testing.T) { mockCluster := cluster mockContainerInstanceARN := containerInstanceARN mockAvailabilityZone := availabilityZone + mockHostPrivateIPv4Address := hostPrivateIPv4Address mockHostPublicIPv4Address := hostPublicIPv4Address mockConfig := &dockercontainer.Config{Image: "image"} @@ -118,10 +125,11 @@ func TestParseHasConfig(t *testing.T) { expectedStatus := string(MetadataReady) newManager := &metadataManager{ - cluster: mockCluster, - containerInstanceARN: mockContainerInstanceARN, - availabilityZone: mockAvailabilityZone, - hostPublicIPv4Address: mockHostPublicIPv4Address, + cluster: mockCluster, + containerInstanceARN: mockContainerInstanceARN, + availabilityZone: mockAvailabilityZone, + hostPrivateIPv4Address: mockHostPrivateIPv4Address, + hostPublicIPv4Address: mockHostPublicIPv4Address, } metadata := newManager.parseMetadata(mockContainer, mockTask, mockContainerName) @@ -131,6 +139,7 @@ func TestParseHasConfig(t *testing.T) { assert.Equal(t, metadata.taskMetadata.taskARN, mockTaskARN, "Expected task ARN "+mockTaskARN) assert.Equal(t, metadata.containerInstanceARN, mockContainerInstanceARN, "Expected container instance ARN "+mockContainerInstanceARN) assert.Equal(t, metadata.availabilityZone, mockAvailabilityZone, "Expected availabilityZone "+mockAvailabilityZone) + assert.Equal(t, metadata.hostPrivateIPv4Address, mockHostPrivateIPv4Address, "Expected hostPrivateIPv4Address "+hostPrivateIPv4Address) assert.Equal(t, metadata.hostPublicIPv4Address, mockHostPublicIPv4Address, "Expected hostPublicIPv4Address "+hostPublicIPv4Address) assert.Equal(t, string(metadata.metadataStatus), expectedStatus, "Expected status "+expectedStatus) assert.Equal(t, metadata.dockerContainerMetadata.imageName, "image", "Expected nonempty imageID") @@ -143,6 +152,7 @@ func TestParseHasNetworkSettingsPortBindings(t *testing.T) { mockCluster := cluster mockContainerInstanceARN := containerInstanceARN mockAvailabilityZone := availabilityZone + mockHostPrivateIPv4Address := hostPrivateIPv4Address mockHostPublicIPv4Address := hostPublicIPv4Address mockPorts := nat.PortMap{} @@ -170,10 +180,11 @@ func TestParseHasNetworkSettingsPortBindings(t *testing.T) { expectedStatus := string(MetadataReady) newManager := &metadataManager{ - cluster: mockCluster, - containerInstanceARN: mockContainerInstanceARN, - availabilityZone: mockAvailabilityZone, - hostPublicIPv4Address: mockHostPublicIPv4Address, + cluster: mockCluster, + containerInstanceARN: mockContainerInstanceARN, + availabilityZone: mockAvailabilityZone, + hostPrivateIPv4Address: mockHostPrivateIPv4Address, + hostPublicIPv4Address: mockHostPublicIPv4Address, } metadata := newManager.parseMetadata(mockContainer, mockTask, mockContainerName) @@ -182,6 +193,7 @@ func TestParseHasNetworkSettingsPortBindings(t *testing.T) { assert.Equal(t, metadata.taskMetadata.taskARN, mockTaskARN, "Expected task ARN "+mockTaskARN) assert.Equal(t, metadata.containerInstanceARN, mockContainerInstanceARN, "Expected container instance ARN "+mockContainerInstanceARN) assert.Equal(t, metadata.availabilityZone, mockAvailabilityZone, "Expected availabilityZone "+mockAvailabilityZone) + assert.Equal(t, metadata.hostPrivateIPv4Address, mockHostPrivateIPv4Address, "Expected hostPrivateIPv4Address "+hostPrivateIPv4Address) assert.Equal(t, metadata.hostPublicIPv4Address, mockHostPublicIPv4Address, "Expected hostPublicIPv4Address "+hostPublicIPv4Address) assert.Equal(t, string(metadata.metadataStatus), expectedStatus, "Expected status "+expectedStatus) assert.Equal(t, len(metadata.dockerContainerMetadata.networkInfo.networks), 2, "Expected two networks") @@ -199,6 +211,7 @@ func TestParseHasNetworkSettingsNetworksEmpty(t *testing.T) { mockCluster := cluster mockContainerInstanceARN := containerInstanceARN mockAvailabilityZone := availabilityZone + mockHostPrivateIPv4Address := hostPrivateIPv4Address mockHostPublicIPv4Address := hostPublicIPv4Address mockHostConfig := &dockercontainer.HostConfig{NetworkMode: "bridge"} @@ -216,10 +229,11 @@ func TestParseHasNetworkSettingsNetworksEmpty(t *testing.T) { expectedStatus := string(MetadataReady) newManager := &metadataManager{ - cluster: mockCluster, - containerInstanceARN: mockContainerInstanceARN, - availabilityZone: mockAvailabilityZone, - hostPublicIPv4Address: mockHostPublicIPv4Address, + cluster: mockCluster, + containerInstanceARN: mockContainerInstanceARN, + availabilityZone: mockAvailabilityZone, + hostPrivateIPv4Address: mockHostPrivateIPv4Address, + hostPublicIPv4Address: mockHostPublicIPv4Address, } metadata := newManager.parseMetadata(mockContainer, mockTask, mockContainerName) @@ -228,6 +242,7 @@ func TestParseHasNetworkSettingsNetworksEmpty(t *testing.T) { assert.Equal(t, metadata.taskMetadata.taskARN, mockTaskARN, "Expected task ARN "+mockTaskARN) assert.Equal(t, metadata.containerInstanceARN, mockContainerInstanceARN, "Expected container instance ARN "+mockContainerInstanceARN) assert.Equal(t, metadata.availabilityZone, mockAvailabilityZone, "Expected availabilityZone "+mockAvailabilityZone) + assert.Equal(t, metadata.hostPrivateIPv4Address, mockHostPrivateIPv4Address, "Expected hostPrivateIPv4Address "+hostPrivateIPv4Address) assert.Equal(t, metadata.hostPublicIPv4Address, mockHostPublicIPv4Address, "Expected hostPublicIPv4Address "+hostPublicIPv4Address) assert.Equal(t, string(metadata.metadataStatus), expectedStatus, "Expected status "+expectedStatus) assert.Equal(t, len(metadata.dockerContainerMetadata.networkInfo.networks), 1, "Expected one network") @@ -240,6 +255,7 @@ func TestParseHasNetworkSettingsNetworksNonEmpty(t *testing.T) { mockCluster := cluster mockContainerInstanceARN := containerInstanceARN mockAvailabilityZone := availabilityZone + mockHostPrivateIPv4Address := hostPrivateIPv4Address mockHostPublicIPv4Address := hostPublicIPv4Address mockHostConfig := &dockercontainer.HostConfig{NetworkMode: dockercontainer.NetworkMode("bridge")} @@ -259,10 +275,11 @@ func TestParseHasNetworkSettingsNetworksNonEmpty(t *testing.T) { expectedStatus := string(MetadataReady) newManager := &metadataManager{ - cluster: mockCluster, - containerInstanceARN: mockContainerInstanceARN, - availabilityZone: mockAvailabilityZone, - hostPublicIPv4Address: mockHostPublicIPv4Address, + cluster: mockCluster, + containerInstanceARN: mockContainerInstanceARN, + availabilityZone: mockAvailabilityZone, + hostPrivateIPv4Address: mockHostPrivateIPv4Address, + hostPublicIPv4Address: mockHostPublicIPv4Address, } metadata := newManager.parseMetadata(mockContainer, mockTask, mockContainerName) @@ -271,6 +288,7 @@ func TestParseHasNetworkSettingsNetworksNonEmpty(t *testing.T) { assert.Equal(t, metadata.taskMetadata.taskARN, mockTaskARN, "Expected task ARN "+mockTaskARN) assert.Equal(t, metadata.containerInstanceARN, mockContainerInstanceARN, "Expected container instance ARN "+mockContainerInstanceARN) assert.Equal(t, metadata.availabilityZone, mockAvailabilityZone, "Expected AvailabilityZone"+mockAvailabilityZone) + assert.Equal(t, metadata.hostPrivateIPv4Address, mockHostPrivateIPv4Address, "Expected hostPrivateIPv4Address "+hostPrivateIPv4Address) assert.Equal(t, metadata.hostPublicIPv4Address, mockHostPublicIPv4Address, "Expected hostPublicIPv4Address "+hostPublicIPv4Address) assert.Equal(t, string(metadata.metadataStatus), expectedStatus, "Expected status "+expectedStatus) assert.Equal(t, len(metadata.dockerContainerMetadata.networkInfo.networks), 2, "Expected two networks") @@ -317,6 +335,7 @@ func TestParseTaskDefinitionSettings(t *testing.T) { mockCluster := cluster mockContainerInstanceARN := containerInstanceARN mockAvailabilityZone := availabilityZone + mockHostPrivateIPv4Address := hostPrivateIPv4Address mockHostPublicIPv4Address := hostPublicIPv4Address mockHostConfig := &dockercontainer.HostConfig{NetworkMode: dockercontainer.NetworkMode("bridge")} @@ -337,10 +356,11 @@ func TestParseTaskDefinitionSettings(t *testing.T) { expectedStatus := string(MetadataReady) newManager := &metadataManager{ - cluster: mockCluster, - containerInstanceARN: mockContainerInstanceARN, - availabilityZone: mockAvailabilityZone, - hostPublicIPv4Address: mockHostPublicIPv4Address, + cluster: mockCluster, + containerInstanceARN: mockContainerInstanceARN, + availabilityZone: mockAvailabilityZone, + hostPrivateIPv4Address: mockHostPrivateIPv4Address, + hostPublicIPv4Address: mockHostPublicIPv4Address, } metadata := newManager.parseMetadata(mockContainer, mockTask, mockContainerName) @@ -351,6 +371,7 @@ func TestParseTaskDefinitionSettings(t *testing.T) { assert.Equal(t, metadata.taskMetadata.taskDefinitionRevision, "", "Expected no task definition revision") assert.Equal(t, metadata.containerInstanceARN, mockContainerInstanceARN, "Expected container instance ARN "+mockContainerInstanceARN) assert.Equal(t, metadata.availabilityZone, mockAvailabilityZone, "Expected availabilityZone "+mockAvailabilityZone) + assert.Equal(t, metadata.hostPrivateIPv4Address, mockHostPrivateIPv4Address, "Expected hostPrivateIPv4Address "+hostPrivateIPv4Address) assert.Equal(t, metadata.hostPublicIPv4Address, mockHostPublicIPv4Address, "Expected hostPublicIPv4Address "+hostPublicIPv4Address) assert.Equal(t, string(metadata.metadataStatus), expectedStatus, "Expected status "+expectedStatus) diff --git a/agent/containermetadata/types.go b/agent/containermetadata/types.go index f0fb947b086..7784e358859 100644 --- a/agent/containermetadata/types.go +++ b/agent/containermetadata/types.go @@ -130,6 +130,7 @@ type Metadata struct { containerInstanceARN string metadataStatus MetadataStatus availabilityZone string + hostPrivateIPv4Address string hostPublicIPv4Address string } @@ -150,6 +151,7 @@ type metadataSerializer struct { Networks []Network `json:"Networks,omitempty"` MetadataFileStatus MetadataStatus `json:"MetadataFileStatus,omitempty"` AvailabilityZone string `json:"AvailabilityZone,omitempty"` + HostPrivateIPv4Address string `json:"HostPrivateIPv4Address,omitempty"` HostPublicIPv4Address string `json:"HostPublicIPv4Address,omitempty"` } @@ -170,6 +172,7 @@ func (m Metadata) MarshalJSON() ([]byte, error) { Networks: m.dockerContainerMetadata.networkInfo.networks, MetadataFileStatus: m.metadataStatus, AvailabilityZone: m.availabilityZone, + HostPrivateIPv4Address: m.hostPrivateIPv4Address, HostPublicIPv4Address: m.hostPublicIPv4Address, }) } diff --git a/agent/ec2/blackhole_ec2_metadata_client.go b/agent/ec2/blackhole_ec2_metadata_client.go index 7ed434f91d6..28137085332 100644 --- a/agent/ec2/blackhole_ec2_metadata_client.go +++ b/agent/ec2/blackhole_ec2_metadata_client.go @@ -65,6 +65,10 @@ func (blackholeMetadataClient) Region() (string, error) { return "", errors.New("blackholed") } +func (blackholeMetadataClient) PrivateIPv4Address() (string, error) { + return "", errors.New("blackholed") +} + func (blackholeMetadataClient) PublicIPv4Address() (string, error) { return "", errors.New("blackholed") } diff --git a/agent/ec2/ec2_metadata_client.go b/agent/ec2/ec2_metadata_client.go index 461653525e0..ca54f95f8be 100644 --- a/agent/ec2/ec2_metadata_client.go +++ b/agent/ec2/ec2_metadata_client.go @@ -33,6 +33,7 @@ const ( VPCIDResourceFormat = "network/interfaces/macs/%s/vpc-id" SubnetIDResourceFormat = "network/interfaces/macs/%s/subnet-id" InstanceIDResource = "instance-id" + PrivateIPv4Resource = "local-ipv4" PublicIPv4Resource = "public-ipv4" ) @@ -71,6 +72,7 @@ type EC2MetadataClient interface { InstanceID() (string, error) GetUserData() (string, error) Region() (string, error) + PrivateIPv4Address() (string, error) PublicIPv4Address() (string, error) } @@ -165,6 +167,13 @@ func (c *ec2MetadataClientImpl) Region() (string, error) { return c.client.Region() } +// PublicIPv4Address returns the public IPv4 of this instance +// if this instance has a public address func (c *ec2MetadataClientImpl) PublicIPv4Address() (string, error) { return c.client.GetMetadata(PublicIPv4Resource) } + +// PrivateIPv4Address returns the private IPv4 of this instance +func (c *ec2MetadataClientImpl) PrivateIPv4Address() (string, error) { + return c.client.GetMetadata(PrivateIPv4Resource) +} diff --git a/agent/ec2/ec2_metadata_client_test.go b/agent/ec2/ec2_metadata_client_test.go index 89501c5a818..541dcd44d3e 100644 --- a/agent/ec2/ec2_metadata_client_test.go +++ b/agent/ec2/ec2_metadata_client_test.go @@ -38,6 +38,7 @@ const ( vpcID = "vpc-1234" subnetID = "subnet-1234" iidRegion = "us-east-1" + privateIP = "127.0.0.1" publicIP = "127.0.0.1" ) @@ -181,6 +182,20 @@ func TestSubnetID(t *testing.T) { assert.Equal(t, subnetID, subnetIDResponse) } +func TestPrivateIPv4Address(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockGetter := mock_ec2.NewMockHttpClient(ctrl) + testClient := ec2.NewEC2MetadataClient(mockGetter) + + mockGetter.EXPECT().GetMetadata( + ec2.PrivateIPv4Resource).Return(privateIP, nil) + privateIPResponse, err := testClient.PrivateIPv4Address() + assert.NoError(t, err) + assert.Equal(t, privateIP, privateIPResponse) +} + func TestPublicIPv4Address(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() diff --git a/agent/ec2/mocks/ec2_mocks.go b/agent/ec2/mocks/ec2_mocks.go index b754460ceaf..722f92f505d 100644 --- a/agent/ec2/mocks/ec2_mocks.go +++ b/agent/ec2/mocks/ec2_mocks.go @@ -141,6 +141,19 @@ func (mr *MockEC2MetadataClientMockRecorder) PrimaryENIMAC() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PrimaryENIMAC", reflect.TypeOf((*MockEC2MetadataClient)(nil).PrimaryENIMAC)) } +// PrivateIPv4Address mocks base method +func (m *MockEC2MetadataClient) PrivateIPv4Address() (string, error) { + ret := m.ctrl.Call(m, "PrivateIPv4Address") + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// PrivateIPv4Address indicates an expected call of PrivateIPv4Address +func (mr *MockEC2MetadataClientMockRecorder) PrivateIPv4Address() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PrivateIPv4Address", reflect.TypeOf((*MockEC2MetadataClient)(nil).PrivateIPv4Address)) +} + // PublicIPv4Address mocks base method func (m *MockEC2MetadataClient) PublicIPv4Address() (string, error) { ret := m.ctrl.Call(m, "PublicIPv4Address") diff --git a/misc/container-metadata-file-validator-windows/container-metadata-file-validator-windows.go b/misc/container-metadata-file-validator-windows/container-metadata-file-validator-windows.go index 54ba71ffb64..78d07205e1a 100644 --- a/misc/container-metadata-file-validator-windows/container-metadata-file-validator-windows.go +++ b/misc/container-metadata-file-validator-windows/container-metadata-file-validator-windows.go @@ -58,6 +58,7 @@ type metadataSerializer struct { Networks []Network `json:"Networks,omitempty"` MetadataFileStatus MetadataStatus `json:"MetadataFileStatus,omitempty"` AvailabilityZone string `json:"AvailabilityZone,omitempty"` + HostPrivateIPv4Address string `json:"HostPrivateIPv4Address,omitempty"` HostPublicIPv4Address string `json:"HostPublicIPv4Address,omitempty"` } @@ -97,7 +98,7 @@ func verifyContainerMetadataResponse(containerMetadataResponseMap map[string]jso "MetadataFileStatus": MetadataReadyText, } // Fields that change dynamically, not predictable - taskExpectedFieldNotEmptyArray := []string{"TaskDefinitionFamily", "Cluster", "ContainerInstanceARN", "TaskARN", "TaskDefinitionRevision", "ContainerID", "DockerContainerName", "ImageID"} + taskExpectedFieldNotEmptyArray := []string{"TaskDefinitionFamily", "Cluster", "ContainerInstanceARN", "TaskARN", "TaskDefinitionRevision", "ContainerID", "DockerContainerName", "ImageID", "HostPrivateIPv4Address"} if hasPublicIp { taskExpectedFieldNotEmptyArray = append(taskExpectedFieldNotEmptyArray, "HostPublicIPv4Address") diff --git a/misc/container-metadata-file-validator/container-metadata-file-validator.go b/misc/container-metadata-file-validator/container-metadata-file-validator.go index 673285ba6e6..66d0fb298e4 100644 --- a/misc/container-metadata-file-validator/container-metadata-file-validator.go +++ b/misc/container-metadata-file-validator/container-metadata-file-validator.go @@ -58,6 +58,7 @@ type metadataSerializer struct { Networks []Network `json:"Networks,omitempty"` MetadataFileStatus MetadataStatus `json:"MetadataFileStatus,omitempty"` AvailabilityZone string `json:"AvailabilityZone,omitempty"` + HostPrivateIPv4Address string `json:"HostPrivateIPv4Address,omitempty"` HostPublicIPv4Address string `json:"HostPublicIPv4Address,omitempty"` } @@ -97,7 +98,7 @@ func verifyContainerMetadataResponse(containerMetadataResponseMap map[string]jso "MetadataFileStatus": MetadataReadyText, } // Fields that change dynamically, not predictable - taskExpectedFieldNotEmptyArray := []string{"TaskDefinitionFamily", "Cluster", "ContainerInstanceARN", "TaskARN", "TaskDefinitionRevision", "ContainerID", "DockerContainerName", "ImageID"} + taskExpectedFieldNotEmptyArray := []string{"TaskDefinitionFamily", "Cluster", "ContainerInstanceARN", "TaskARN", "TaskDefinitionRevision", "ContainerID", "DockerContainerName", "ImageID", "HostPrivateIPv4Address"} if hasPublicIp { taskExpectedFieldNotEmptyArray = append(taskExpectedFieldNotEmptyArray, "HostPublicIPv4Address")