diff --git a/agent/api/ecsclient/client.go b/agent/api/ecsclient/client.go index bef4ffc5c36..ec085aa2c09 100644 --- a/agent/api/ecsclient/client.go +++ b/agent/api/ecsclient/client.go @@ -110,8 +110,10 @@ func (client *APIECSClient) CreateCluster(clusterName string) (string, error) { // ContainerInstanceARN if successful. Supplying a non-empty container // instance ARN allows a container instance to update its registered // resources. -func (client *APIECSClient) RegisterContainerInstance(containerInstanceArn string, - attributes []*ecs.Attribute, tags []*ecs.Tag, registrationToken string, platformDevices []*ecs.PlatformDevice) (string, string, error) { +func (client *APIECSClient) RegisterContainerInstance(containerInstanceArn string, attributes []*ecs.Attribute, + tags []*ecs.Tag, registrationToken string, platformDevices []*ecs.PlatformDevice, + outpostARN string) (string, string, error) { + clusterRef := client.config.Cluster // If our clusterRef is empty, we should try to create the default if clusterRef == "" { @@ -122,7 +124,8 @@ func (client *APIECSClient) RegisterContainerInstance(containerInstanceArn strin }() // Attempt to register without checking existence of the cluster so we don't require // excess permissions in the case where the cluster already exists and is active - containerInstanceArn, availabilityzone, err := client.registerContainerInstance(clusterRef, containerInstanceArn, attributes, tags, registrationToken, platformDevices) + containerInstanceArn, availabilityzone, err := client.registerContainerInstance(clusterRef, + containerInstanceArn, attributes, tags, registrationToken, platformDevices, outpostARN) if err == nil { return containerInstanceArn, availabilityzone, nil } @@ -136,11 +139,14 @@ func (client *APIECSClient) RegisterContainerInstance(containerInstanceArn strin } } } - return client.registerContainerInstance(clusterRef, containerInstanceArn, attributes, tags, registrationToken, platformDevices) + return client.registerContainerInstance(clusterRef, containerInstanceArn, attributes, tags, registrationToken, + platformDevices, outpostARN) } func (client *APIECSClient) registerContainerInstance(clusterRef string, containerInstanceArn string, - attributes []*ecs.Attribute, tags []*ecs.Tag, registrationToken string, platformDevices []*ecs.PlatformDevice) (string, string, error) { + attributes []*ecs.Attribute, tags []*ecs.Tag, registrationToken string, + platformDevices []*ecs.PlatformDevice, outpostARN string) (string, string, error) { + registerRequest := ecs.RegisterContainerInstanceInput{Cluster: &clusterRef} var registrationAttributes []*ecs.Attribute if containerInstanceArn != "" { @@ -162,6 +168,8 @@ func (client *APIECSClient) registerContainerInstance(clusterRef string, contain // Add additional attributes such as the os type registrationAttributes = append(registrationAttributes, client.getAdditionalAttributes()...) + registrationAttributes = append(registrationAttributes, client.getOutpostAttribute(outpostARN)...) + registerRequest.Attributes = registrationAttributes if len(tags) > 0 { registerRequest.Tags = tags @@ -317,10 +325,24 @@ func validateRegisteredAttributes(expectedAttributes, actualAttributes []*ecs.At } func (client *APIECSClient) getAdditionalAttributes() []*ecs.Attribute { - return []*ecs.Attribute{{ - Name: aws.String("ecs.os-type"), - Value: aws.String(config.OSType), - }} + return []*ecs.Attribute{ + { + Name: aws.String("ecs.os-type"), + Value: aws.String(config.OSType), + }, + } +} + +func (client *APIECSClient) getOutpostAttribute(outpostARN string) []*ecs.Attribute { + if len(outpostARN) > 0 { + return []*ecs.Attribute{ + { + Name: aws.String("ecs.outpost-arn"), + Value: aws.String(outpostARN), + }, + } + } + return []*ecs.Attribute{} } func (client *APIECSClient) getCustomAttributes() []*ecs.Attribute { diff --git a/agent/api/ecsclient/client_test.go b/agent/api/ecsclient/client_test.go index 314b41a2572..332960efed2 100644 --- a/agent/api/ecsclient/client_test.go +++ b/agent/api/ecsclient/client_test.go @@ -64,6 +64,7 @@ var ( }, } containerInstanceTagsMap = map[string]string{ + "my_key1": "my_val1", "my_key2": "my_val2", } @@ -336,6 +337,7 @@ func TestReRegisterContainerInstance(t *testing.T) { expectedAttributes := map[string]string{ "ecs.os-type": config.OSType, "ecs.availability-zone": "us-west-2b", + "ecs.outpost-arn": "test:arn:outpost", } for i := range fakeCapabilities { expectedAttributes[fakeCapabilities[i]] = "" @@ -355,8 +357,8 @@ func TestReRegisterContainerInstance(t *testing.T) { resource, ok := findResource(req.TotalResources, "PORTS_UDP") assert.True(t, ok, `Could not find resource "PORTS_UDP"`) assert.Equal(t, "STRINGSET", *resource.Type, `Wrong type for resource "PORTS_UDP"`) - // "ecs.os-type" and the 2 that we specified as additionalAttributes - assert.Equal(t, 3, len(req.Attributes), "Wrong number of Attributes") + // "ecs.os-type", ecs.outpost-arn and the 2 that we specified as additionalAttributes + assert.Equal(t, 4, len(req.Attributes), "Wrong number of Attributes") reqAttributes := func() map[string]string { rv := make(map[string]string, len(req.Attributes)) for i := range req.Attributes { @@ -382,7 +384,8 @@ func TestReRegisterContainerInstance(t *testing.T) { nil), ) - arn, availabilityzone, err := client.RegisterContainerInstance("arn:test", capabilities, containerInstanceTags, registrationToken, nil) + arn, availabilityzone, err := client.RegisterContainerInstance("arn:test", capabilities, + containerInstanceTags, registrationToken, nil, "test:arn:outpost") assert.NoError(t, err) assert.Equal(t, "registerArn", arn) @@ -404,6 +407,7 @@ func TestRegisterContainerInstance(t *testing.T) { "my_custom_attribute": "Custom_Value1", "my_other_custom_attribute": "Custom_Value2", "ecs.availability-zone": "us-west-2b", + "ecs.outpost-arn": "test:arn:outpost", } capabilities := buildAttributeList(fakeCapabilities, nil) platformDevices := []*ecs.PlatformDevice{ @@ -434,8 +438,8 @@ func TestRegisterContainerInstance(t *testing.T) { resource, ok := findResource(req.TotalResources, "PORTS_UDP") assert.True(t, ok, `Could not find resource "PORTS_UDP"`) assert.Equal(t, "STRINGSET", *resource.Type, `Wrong type for resource "PORTS_UDP"`) - // 3 from expectedAttributes and 2 from additionalAttributes - assert.Equal(t, 5, len(req.Attributes), "Wrong number of Attributes") + // 3 from expectedAttributes and 3 from additionalAttributes + assert.Equal(t, 6, len(req.Attributes), "Wrong number of Attributes") for i := range req.Attributes { if strings.Contains(*req.Attributes[i].Name, "capability") { assert.Contains(t, fakeCapabilities, *req.Attributes[i].Name) @@ -457,7 +461,8 @@ func TestRegisterContainerInstance(t *testing.T) { nil), ) - arn, availabilityzone, err := client.RegisterContainerInstance("", capabilities, containerInstanceTags, registrationToken, platformDevices) + arn, availabilityzone, err := client.RegisterContainerInstance("", capabilities, + containerInstanceTags, registrationToken, platformDevices, "test:arn:outpost") assert.NoError(t, err) assert.Equal(t, "registerArn", arn) assert.Equal(t, "us-west-2b", availabilityzone) @@ -484,6 +489,7 @@ func TestRegisterContainerInstanceNoIID(t *testing.T) { "my_custom_attribute": "Custom_Value1", "my_other_custom_attribute": "Custom_Value2", "ecs.availability-zone": "us-west-2b", + "ecs.outpost-arn": "test:arn:outpost", } capabilities := buildAttributeList(fakeCapabilities, nil) @@ -498,8 +504,8 @@ func TestRegisterContainerInstanceNoIID(t *testing.T) { resource, ok := findResource(req.TotalResources, "PORTS_UDP") assert.True(t, ok, `Could not find resource "PORTS_UDP"`) assert.Equal(t, "STRINGSET", *resource.Type, `Wrong type for resource "PORTS_UDP"`) - // 3 from expectedAttributes and 2 from additionalAttributes - assert.Equal(t, 5, len(req.Attributes), "Wrong number of Attributes") + // 3 from expectedAttributes and 3 from additionalAttributes + assert.Equal(t, 6, len(req.Attributes), "Wrong number of Attributes") for i := range req.Attributes { if strings.Contains(*req.Attributes[i].Name, "capability") { assert.Contains(t, fakeCapabilities, *req.Attributes[i].Name) @@ -520,7 +526,8 @@ func TestRegisterContainerInstanceNoIID(t *testing.T) { nil), ) - arn, availabilityzone, err := client.RegisterContainerInstance("", capabilities, containerInstanceTags, registrationToken, nil) + arn, availabilityzone, err := client.RegisterContainerInstance("", capabilities, + containerInstanceTags, registrationToken, nil, "test:arn:outpost") assert.NoError(t, err) assert.Equal(t, "registerArn", arn) assert.Equal(t, "us-west-2b", availabilityzone) @@ -547,7 +554,8 @@ func TestRegisterContainerInstanceWithNegativeResource(t *testing.T) { mockEC2Metadata.EXPECT().GetDynamicData(ec2.InstanceIdentityDocumentResource).Return("instanceIdentityDocument", nil), mockEC2Metadata.EXPECT().GetDynamicData(ec2.InstanceIdentityDocumentSignatureResource).Return("signature", nil), ) - _, _, err := client.RegisterContainerInstance("", nil, nil, "", nil) + _, _, err := client.RegisterContainerInstance("", nil, nil, + "", nil, "") assert.Error(t, err, "Register resource with negative value should cause registration fail") } @@ -577,7 +585,8 @@ func TestRegisterContainerInstanceWithEmptyTags(t *testing.T) { nil), ) - _, _, err := client.RegisterContainerInstance("", nil, make([]*ecs.Tag, 0), "", nil) + _, _, err := client.RegisterContainerInstance("", nil, make([]*ecs.Tag, 0), + "", nil, "") assert.NoError(t, err) } @@ -651,7 +660,8 @@ func TestRegisterBlankCluster(t *testing.T) { nil), ) - arn, availabilityzone, err := client.RegisterContainerInstance("", nil, nil, "", nil) + arn, availabilityzone, err := client.RegisterContainerInstance("", nil, nil, + "", nil, "") if err != nil { t.Errorf("Should not be an error: %v", err) } @@ -705,7 +715,8 @@ func TestRegisterBlankClusterNotCreatingClusterWhenErrorNotClusterNotFound(t *te nil), ) - arn, _, err := client.RegisterContainerInstance("", nil, nil, "", nil) + arn, _, err := client.RegisterContainerInstance("", nil, nil, "", + nil, "") assert.NoError(t, err, "Should not return error") assert.Equal(t, "registerArn", arn, "Wrong arn") } diff --git a/agent/api/interface.go b/agent/api/interface.go index 54404962d9e..3e06ed35e8a 100644 --- a/agent/api/interface.go +++ b/agent/api/interface.go @@ -27,7 +27,8 @@ type ECSClient interface { // instance ARN allows a container instance to update its registered // resources. RegisterContainerInstance(existingContainerInstanceArn string, - attributes []*ecs.Attribute, tags []*ecs.Tag, registrationToken string, platformDevices []*ecs.PlatformDevice) (string, string, error) + attributes []*ecs.Attribute, tags []*ecs.Tag, registrationToken string, platformDevices []*ecs.PlatformDevice, + outpostARN string) (string, string, error) // SubmitTaskStateChange sends a state change and returns an error // indicating if it was submitted SubmitTaskStateChange(change TaskStateChange) error diff --git a/agent/api/mocks/api_mocks.go b/agent/api/mocks/api_mocks.go index c06e75bd0dd..1f75128d6e9 100644 --- a/agent/api/mocks/api_mocks.go +++ b/agent/api/mocks/api_mocks.go @@ -261,9 +261,9 @@ func (mr *MockECSClientMockRecorder) GetResourceTags(arg0 interface{}) *gomock.C } // RegisterContainerInstance mocks base method -func (m *MockECSClient) RegisterContainerInstance(arg0 string, arg1 []*ecs.Attribute, arg2 []*ecs.Tag, arg3 string, arg4 []*ecs.PlatformDevice) (string, string, error) { +func (m *MockECSClient) RegisterContainerInstance(arg0 string, arg1 []*ecs.Attribute, arg2 []*ecs.Tag, arg3 string, arg4 []*ecs.PlatformDevice, arg5 string) (string, string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RegisterContainerInstance", arg0, arg1, arg2, arg3, arg4) + ret := m.ctrl.Call(m, "RegisterContainerInstance", arg0, arg1, arg2, arg3, arg4, arg5) ret0, _ := ret[0].(string) ret1, _ := ret[1].(string) ret2, _ := ret[2].(error) @@ -271,9 +271,9 @@ func (m *MockECSClient) RegisterContainerInstance(arg0 string, arg1 []*ecs.Attri } // RegisterContainerInstance indicates an expected call of RegisterContainerInstance -func (mr *MockECSClientMockRecorder) RegisterContainerInstance(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { +func (mr *MockECSClientMockRecorder) RegisterContainerInstance(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterContainerInstance", reflect.TypeOf((*MockECSClient)(nil).RegisterContainerInstance), arg0, arg1, arg2, arg3, arg4) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterContainerInstance", reflect.TypeOf((*MockECSClient)(nil).RegisterContainerInstance), arg0, arg1, arg2, arg3, arg4, arg5) } // SubmitAttachmentStateChange mocks base method diff --git a/agent/app/agent.go b/agent/app/agent.go index c0b45fbed6b..aa083abda25 100644 --- a/agent/app/agent.go +++ b/agent/app/agent.go @@ -435,6 +435,17 @@ func (agent *ecsAgent) getEC2InstanceID() string { return instanceID } +// getoutpostARN gets the Outpost ARN from the metadata service +func (agent *ecsAgent) getoutpostARN() string { + outpostARN, err := agent.ec2MetadataClient.OutpostARN() + if err != nil { + seelog.Warnf( + "Unable to obtain Outpost ARN from EC2 Metadata: %v", err) + return "" + } + return outpostARN +} + // newStateManager creates a new state manager object for the task engine. // Rest of the parameters are pointers and it's expected that all of these // will be backfilled when state manager's Load() method is invoked @@ -508,13 +519,16 @@ func (agent *ecsAgent) registerContainerInstance( platformDevices := agent.getPlatformDevices() + outpostARN := agent.getoutpostARN() + if agent.containerInstanceARN != "" { seelog.Infof("Restored from checkpoint file. I am running as '%s' in cluster '%s'", agent.containerInstanceARN, agent.cfg.Cluster) - return agent.reregisterContainerInstance(client, capabilities, tags, uuid.New(), platformDevices) + return agent.reregisterContainerInstance(client, capabilities, tags, uuid.New(), platformDevices, outpostARN) } seelog.Info("Registering Instance with ECS") - containerInstanceArn, availabilityZone, err := client.RegisterContainerInstance("", capabilities, tags, uuid.New(), platformDevices) + containerInstanceArn, availabilityZone, err := client.RegisterContainerInstance("", + capabilities, tags, uuid.New(), platformDevices, outpostARN) if err != nil { seelog.Errorf("Error registering: %v", err) if retriable, ok := err.(apierrors.Retriable); ok && !retriable.Retry() { @@ -541,9 +555,11 @@ func (agent *ecsAgent) registerContainerInstance( // reregisterContainerInstance registers a container instance that has already been // registered with ECS. This is for cases where the ECS Agent is being restored // from a check point. -func (agent *ecsAgent) reregisterContainerInstance(client api.ECSClient, - capabilities []*ecs.Attribute, tags []*ecs.Tag, registrationToken string, platformDevices []*ecs.PlatformDevice) error { - _, availabilityZone, err := client.RegisterContainerInstance(agent.containerInstanceARN, capabilities, tags, registrationToken, platformDevices) +func (agent *ecsAgent) reregisterContainerInstance(client api.ECSClient, capabilities []*ecs.Attribute, + tags []*ecs.Tag, registrationToken string, platformDevices []*ecs.PlatformDevice, outpostARN string) error { + _, availabilityZone, err := client.RegisterContainerInstance(agent.containerInstanceARN, capabilities, tags, + registrationToken, platformDevices, outpostARN) + //set az to agent agent.availabilityZone = availabilityZone diff --git a/agent/app/agent_test.go b/agent/app/agent_test.go index 70cde1bac3a..1f8028bf9f4 100644 --- a/agent/app/agent_test.go +++ b/agent/app/agent_test.go @@ -232,6 +232,7 @@ func TestDoStartRegisterContainerInstanceErrorTerminal(t *testing.T) { mockCredentialsProvider := app_mocks.NewMockProvider(ctrl) mockMobyPlugins := mock_mobypkgwrapper.NewMockPlugins(ctrl) + mockEC2Metadata := mock_ec2.NewMockEC2MetadataClient(ctrl) gomock.InOrder( dockerClient.EXPECT().SupportedVersions().Return(apiVersions), @@ -241,10 +242,12 @@ func TestDoStartRegisterContainerInstanceErrorTerminal(t *testing.T) { mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{""}, nil), dockerClient.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return([]string{}, nil), - client.EXPECT().RegisterContainerInstance(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return( - "", "", apierrors.NewAttributeError("error")), + client.EXPECT().RegisterContainerInstance(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), + gomock.Any()).Return("", "", apierrors.NewAttributeError("error")), ) + mockEC2Metadata.EXPECT().OutpostARN().Return("", nil) + cfg := getTestConfig() cfg.TaskCPUMemLimit = config.ExplicitlyDisabled ctx, cancel := context.WithCancel(context.TODO()) @@ -256,6 +259,7 @@ func TestDoStartRegisterContainerInstanceErrorTerminal(t *testing.T) { credentialProvider: aws_credentials.NewCredentials(mockCredentialsProvider), dockerClient: dockerClient, mobyPlugins: mockMobyPlugins, + ec2MetadataClient: mockEC2Metadata, } exitCode := agent.doStart(eventstream.NewEventStream("events", ctx), @@ -268,8 +272,9 @@ func TestDoStartRegisterContainerInstanceErrorNonTerminal(t *testing.T) { dockerClient, _, _ := setup(t) defer ctrl.Finish() mockMobyPlugins := mock_mobypkgwrapper.NewMockPlugins(ctrl) - mockCredentialsProvider := app_mocks.NewMockProvider(ctrl) + mockEC2Metadata := mock_ec2.NewMockEC2MetadataClient(ctrl) + gomock.InOrder( dockerClient.EXPECT().SupportedVersions().Return(apiVersions), mockCredentialsProvider.EXPECT().Retrieve().Return(aws_credentials.Value{}, nil), @@ -278,10 +283,12 @@ func TestDoStartRegisterContainerInstanceErrorNonTerminal(t *testing.T) { mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{""}, nil), dockerClient.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return([]string{}, nil), - client.EXPECT().RegisterContainerInstance(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return( - "", "", errors.New("error")), + client.EXPECT().RegisterContainerInstance(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), + gomock.Any()).Return("", "", errors.New("error")), ) + mockEC2Metadata.EXPECT().OutpostARN().Return("", nil) + cfg := getTestConfig() ctx, cancel := context.WithCancel(context.TODO()) // Cancel the context to cancel async routines @@ -292,6 +299,7 @@ func TestDoStartRegisterContainerInstanceErrorNonTerminal(t *testing.T) { dockerClient: dockerClient, credentialProvider: aws_credentials.NewCredentials(mockCredentialsProvider), mobyPlugins: mockMobyPlugins, + ec2MetadataClient: mockEC2Metadata, } exitCode := agent.doStart(eventstream.NewEventStream("events", ctx), @@ -307,6 +315,7 @@ func TestDoStartRegisterAvailabilityZone(t *testing.T) { ec2MetadataClient := mock_ec2.NewMockEC2MetadataClient(ctrl) ec2MetadataClient.EXPECT().PrivateIPv4Address().Return(hostPrivateIPv4Address, nil) ec2MetadataClient.EXPECT().PublicIPv4Address().Return(hostPublicIPv4Address, nil) + ec2MetadataClient.EXPECT().OutpostARN().Return("", nil) var discoverEndpointsInvoked sync.WaitGroup discoverEndpointsInvoked.Add(2) @@ -337,8 +346,8 @@ func TestDoStartRegisterAvailabilityZone(t *testing.T) { mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{""}, nil), dockerClient.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return([]string{}, nil), - client.EXPECT().RegisterContainerInstance(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return( - "arn:123", availabilityZone, nil), + client.EXPECT().RegisterContainerInstance(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), + gomock.Any(), gomock.Any()).Return("arn:123", availabilityZone, nil), containermetadata.EXPECT().SetContainerInstanceARN("arn:123"), containermetadata.EXPECT().SetAvailabilityZone(availabilityZone), containermetadata.EXPECT().SetHostPrivateIPv4Address(hostPrivateIPv4Address), @@ -675,6 +684,17 @@ func TestGetEC2InstanceIDIIDError(t *testing.T) { assert.Equal(t, "", agent.getEC2InstanceID()) } +func TestGetOupostIDError(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + ec2MetadataClient := mock_ec2.NewMockEC2MetadataClient(ctrl) + agent := &ecsAgent{ec2MetadataClient: ec2MetadataClient} + + ec2MetadataClient.EXPECT().OutpostARN().Return("", errors.New("error")) + assert.Equal(t, "", agent.getoutpostARN()) +} + func TestReregisterContainerInstanceHappyPath(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() @@ -684,6 +704,7 @@ func TestReregisterContainerInstanceHappyPath(t *testing.T) { client := mock_api.NewMockECSClient(ctrl) mockCredentialsProvider := app_mocks.NewMockProvider(ctrl) mockMobyPlugins := mock_mobypkgwrapper.NewMockPlugins(ctrl) + mockEC2Metadata := mock_ec2.NewMockEC2MetadataClient(ctrl) gomock.InOrder( mockCredentialsProvider.EXPECT().Retrieve().Return(aws_credentials.Value{}, nil), @@ -692,7 +713,7 @@ func TestReregisterContainerInstanceHappyPath(t *testing.T) { mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{""}, nil), mockDockerClient.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return([]string{}, nil), - client.EXPECT().RegisterContainerInstance(containerInstanceARN, gomock.Any(), + client.EXPECT().RegisterContainerInstance(containerInstanceARN, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(containerInstanceARN, availabilityZone, nil), ) cfg := getTestConfig() @@ -700,12 +721,16 @@ func TestReregisterContainerInstanceHappyPath(t *testing.T) { ctx, cancel := context.WithCancel(context.TODO()) // Cancel the context to cancel async routines defer cancel() + + mockEC2Metadata.EXPECT().OutpostARN().Return("", nil) + agent := &ecsAgent{ ctx: ctx, cfg: &cfg, dockerClient: mockDockerClient, credentialProvider: aws_credentials.NewCredentials(mockCredentialsProvider), mobyPlugins: mockMobyPlugins, + ec2MetadataClient: mockEC2Metadata, } agent.containerInstanceARN = containerInstanceARN agent.availabilityZone = availabilityZone @@ -723,6 +748,7 @@ func TestReregisterContainerInstanceInstanceTypeChanged(t *testing.T) { client := mock_api.NewMockECSClient(ctrl) mockCredentialsProvider := app_mocks.NewMockProvider(ctrl) mockMobyPlugins := mock_mobypkgwrapper.NewMockPlugins(ctrl) + mockEC2Metadata := mock_ec2.NewMockEC2MetadataClient(ctrl) gomock.InOrder( mockCredentialsProvider.EXPECT().Retrieve().Return(aws_credentials.Value{}, nil), @@ -731,8 +757,9 @@ func TestReregisterContainerInstanceInstanceTypeChanged(t *testing.T) { mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{""}, nil), mockDockerClient.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return([]string{}, nil), - client.EXPECT().RegisterContainerInstance(containerInstanceARN, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return( - "", "", awserr.New("", apierrors.InstanceTypeChangedErrorMessage, errors.New(""))), + client.EXPECT().RegisterContainerInstance(containerInstanceARN, gomock.Any(), gomock.Any(), gomock.Any(), + gomock.Any(), gomock.Any()).Return("", "", awserr.New("", + apierrors.InstanceTypeChangedErrorMessage, errors.New(""))), ) cfg := getTestConfig() @@ -740,11 +767,14 @@ func TestReregisterContainerInstanceInstanceTypeChanged(t *testing.T) { ctx, cancel := context.WithCancel(context.TODO()) // Cancel the context to cancel async routines defer cancel() + mockEC2Metadata.EXPECT().OutpostARN().Return("", nil) + agent := &ecsAgent{ ctx: ctx, cfg: &cfg, dockerClient: mockDockerClient, credentialProvider: aws_credentials.NewCredentials(mockCredentialsProvider), + ec2MetadataClient: mockEC2Metadata, mobyPlugins: mockMobyPlugins, } agent.containerInstanceARN = containerInstanceARN @@ -764,6 +794,7 @@ func TestReregisterContainerInstanceAttributeError(t *testing.T) { client := mock_api.NewMockECSClient(ctrl) mockCredentialsProvider := app_mocks.NewMockProvider(ctrl) mockMobyPlugins := mock_mobypkgwrapper.NewMockPlugins(ctrl) + mockEC2Metadata := mock_ec2.NewMockEC2MetadataClient(ctrl) gomock.InOrder( mockCredentialsProvider.EXPECT().Retrieve().Return(aws_credentials.Value{}, nil), @@ -772,9 +803,10 @@ func TestReregisterContainerInstanceAttributeError(t *testing.T) { mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{}, nil), mockDockerClient.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return([]string{}, nil), - client.EXPECT().RegisterContainerInstance(containerInstanceARN, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return( - "", "", apierrors.NewAttributeError("error")), + client.EXPECT().RegisterContainerInstance(containerInstanceARN, gomock.Any(), gomock.Any(), gomock.Any(), + gomock.Any(), gomock.Any()).Return("", "", apierrors.NewAttributeError("error")), ) + mockEC2Metadata.EXPECT().OutpostARN().Return("", nil) cfg := getTestConfig() cfg.Cluster = clusterName @@ -784,6 +816,7 @@ func TestReregisterContainerInstanceAttributeError(t *testing.T) { agent := &ecsAgent{ ctx: ctx, cfg: &cfg, + ec2MetadataClient: mockEC2Metadata, dockerClient: mockDockerClient, credentialProvider: aws_credentials.NewCredentials(mockCredentialsProvider), mobyPlugins: mockMobyPlugins, @@ -805,6 +838,7 @@ func TestReregisterContainerInstanceNonTerminalError(t *testing.T) { client := mock_api.NewMockECSClient(ctrl) mockCredentialsProvider := app_mocks.NewMockProvider(ctrl) mockMobyPlugins := mock_mobypkgwrapper.NewMockPlugins(ctrl) + mockEC2Metadata := mock_ec2.NewMockEC2MetadataClient(ctrl) gomock.InOrder( mockCredentialsProvider.EXPECT().Retrieve().Return(aws_credentials.Value{}, nil), @@ -813,9 +847,10 @@ func TestReregisterContainerInstanceNonTerminalError(t *testing.T) { mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{}, nil), mockDockerClient.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return([]string{}, nil), - client.EXPECT().RegisterContainerInstance(containerInstanceARN, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return( - "", "", errors.New("error")), + client.EXPECT().RegisterContainerInstance(containerInstanceARN, gomock.Any(), gomock.Any(), gomock.Any(), + gomock.Any(), gomock.Any()).Return("", "", errors.New("error")), ) + mockEC2Metadata.EXPECT().OutpostARN().Return("", nil) cfg := getTestConfig() cfg.Cluster = clusterName @@ -826,6 +861,7 @@ func TestReregisterContainerInstanceNonTerminalError(t *testing.T) { ctx: ctx, cfg: &cfg, dockerClient: mockDockerClient, + ec2MetadataClient: mockEC2Metadata, credentialProvider: aws_credentials.NewCredentials(mockCredentialsProvider), mobyPlugins: mockMobyPlugins, } @@ -846,6 +882,7 @@ func TestRegisterContainerInstanceWhenContainerInstanceARNIsNotSetHappyPath(t *t client := mock_api.NewMockECSClient(ctrl) mockCredentialsProvider := app_mocks.NewMockProvider(ctrl) mockMobyPlugins := mock_mobypkgwrapper.NewMockPlugins(ctrl) + mockEC2Metadata := mock_ec2.NewMockEC2MetadataClient(ctrl) gomock.InOrder( mockCredentialsProvider.EXPECT().Retrieve().Return(aws_credentials.Value{}, nil), @@ -854,9 +891,10 @@ func TestRegisterContainerInstanceWhenContainerInstanceARNIsNotSetHappyPath(t *t mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{}, nil), mockDockerClient.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return([]string{}, nil), - client.EXPECT().RegisterContainerInstance("", gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(containerInstanceARN, availabilityZone, nil), - stateManager.EXPECT().Save(), + client.EXPECT().RegisterContainerInstance("", gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), + gomock.Any()).Return(containerInstanceARN, availabilityZone, nil), stateManager.EXPECT().Save(), ) + mockEC2Metadata.EXPECT().OutpostARN().Return("", nil) cfg := getTestConfig() cfg.Cluster = clusterName @@ -867,6 +905,7 @@ func TestRegisterContainerInstanceWhenContainerInstanceARNIsNotSetHappyPath(t *t ctx: ctx, cfg: &cfg, dockerClient: mockDockerClient, + ec2MetadataClient: mockEC2Metadata, credentialProvider: aws_credentials.NewCredentials(mockCredentialsProvider), mobyPlugins: mockMobyPlugins, } @@ -885,6 +924,7 @@ func TestRegisterContainerInstanceWhenContainerInstanceARNIsNotSetCanRetryError( client := mock_api.NewMockECSClient(ctrl) mockCredentialsProvider := app_mocks.NewMockProvider(ctrl) mockMobyPlugins := mock_mobypkgwrapper.NewMockPlugins(ctrl) + mockEC2Metadata := mock_ec2.NewMockEC2MetadataClient(ctrl) retriableError := apierrors.NewRetriableError(apierrors.NewRetriable(true), errors.New("error")) gomock.InOrder( @@ -894,8 +934,10 @@ func TestRegisterContainerInstanceWhenContainerInstanceARNIsNotSetCanRetryError( mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{}, nil), mockDockerClient.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return([]string{}, nil), - client.EXPECT().RegisterContainerInstance("", gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return("", "", retriableError), + client.EXPECT().RegisterContainerInstance("", gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), + gomock.Any()).Return("", "", retriableError), ) + mockEC2Metadata.EXPECT().OutpostARN().Return("", nil) cfg := getTestConfig() cfg.Cluster = clusterName @@ -906,6 +948,7 @@ func TestRegisterContainerInstanceWhenContainerInstanceARNIsNotSetCanRetryError( ctx: ctx, cfg: &cfg, dockerClient: mockDockerClient, + ec2MetadataClient: mockEC2Metadata, credentialProvider: aws_credentials.NewCredentials(mockCredentialsProvider), mobyPlugins: mockMobyPlugins, } @@ -924,6 +967,7 @@ func TestRegisterContainerInstanceWhenContainerInstanceARNIsNotSetCannotRetryErr client := mock_api.NewMockECSClient(ctrl) mockCredentialsProvider := app_mocks.NewMockProvider(ctrl) mockMobyPlugins := mock_mobypkgwrapper.NewMockPlugins(ctrl) + mockEC2Metadata := mock_ec2.NewMockEC2MetadataClient(ctrl) cannotRetryError := apierrors.NewRetriableError(apierrors.NewRetriable(false), errors.New("error")) gomock.InOrder( @@ -933,8 +977,10 @@ func TestRegisterContainerInstanceWhenContainerInstanceARNIsNotSetCannotRetryErr mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{}, nil), mockDockerClient.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return([]string{}, nil), - client.EXPECT().RegisterContainerInstance("", gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return("", "", cannotRetryError), + client.EXPECT().RegisterContainerInstance("", gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), + gomock.Any()).Return("", "", cannotRetryError), ) + mockEC2Metadata.EXPECT().OutpostARN().Return("", nil) cfg := getTestConfig() cfg.Cluster = clusterName @@ -944,6 +990,7 @@ func TestRegisterContainerInstanceWhenContainerInstanceARNIsNotSetCannotRetryErr agent := &ecsAgent{ ctx: ctx, cfg: &cfg, + ec2MetadataClient: mockEC2Metadata, dockerClient: mockDockerClient, credentialProvider: aws_credentials.NewCredentials(mockCredentialsProvider), mobyPlugins: mockMobyPlugins, @@ -963,6 +1010,7 @@ func TestRegisterContainerInstanceWhenContainerInstanceARNIsNotSetAttributeError client := mock_api.NewMockECSClient(ctrl) mockCredentialsProvider := app_mocks.NewMockProvider(ctrl) mockMobyPlugins := mock_mobypkgwrapper.NewMockPlugins(ctrl) + mockEC2Metadata := mock_ec2.NewMockEC2MetadataClient(ctrl) gomock.InOrder( mockCredentialsProvider.EXPECT().Retrieve().Return(aws_credentials.Value{}, nil), @@ -971,9 +1019,10 @@ func TestRegisterContainerInstanceWhenContainerInstanceARNIsNotSetAttributeError mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{}, nil), mockDockerClient.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return([]string{}, nil), - client.EXPECT().RegisterContainerInstance("", gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return( - "", "", apierrors.NewAttributeError("error")), + client.EXPECT().RegisterContainerInstance("", gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), + gomock.Any()).Return("", "", apierrors.NewAttributeError("error")), ) + mockEC2Metadata.EXPECT().OutpostARN().Return("", nil) cfg := getTestConfig() cfg.Cluster = clusterName @@ -983,6 +1032,7 @@ func TestRegisterContainerInstanceWhenContainerInstanceARNIsNotSetAttributeError agent := &ecsAgent{ ctx: ctx, cfg: &cfg, + ec2MetadataClient: mockEC2Metadata, dockerClient: mockDockerClient, credentialProvider: aws_credentials.NewCredentials(mockCredentialsProvider), mobyPlugins: mockMobyPlugins, @@ -1000,6 +1050,7 @@ func TestRegisterContainerInstanceInvalidParameterTerminalError(t *testing.T) { mockCredentialsProvider := app_mocks.NewMockProvider(ctrl) mockMobyPlugins := mock_mobypkgwrapper.NewMockPlugins(ctrl) + mockEC2Metadata := mock_ec2.NewMockEC2MetadataClient(ctrl) gomock.InOrder( dockerClient.EXPECT().SupportedVersions().Return(apiVersions), @@ -1009,9 +1060,10 @@ func TestRegisterContainerInstanceInvalidParameterTerminalError(t *testing.T) { mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{}, nil), dockerClient.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return([]string{}, nil), - client.EXPECT().RegisterContainerInstance(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return( - "", "", awserr.New("InvalidParameterException", "", nil)), + client.EXPECT().RegisterContainerInstance(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), + gomock.Any()).Return("", "", awserr.New("InvalidParameterException", "", nil)), ) + mockEC2Metadata.EXPECT().OutpostARN().Return("", nil) cfg := getTestConfig() ctx, cancel := context.WithCancel(context.TODO()) @@ -1019,6 +1071,7 @@ func TestRegisterContainerInstanceInvalidParameterTerminalError(t *testing.T) { defer cancel() agent := &ecsAgent{ ctx: ctx, + ec2MetadataClient: mockEC2Metadata, cfg: &cfg, credentialProvider: aws_credentials.NewCredentials(mockCredentialsProvider), dockerClient: dockerClient, diff --git a/agent/app/agent_unix_test.go b/agent/app/agent_unix_test.go index c20d818e38c..089fa43437f 100644 --- a/agent/app/agent_unix_test.go +++ b/agent/app/agent_unix_test.go @@ -57,10 +57,10 @@ const ( ) func TestDoStartHappyPath(t *testing.T) { - ctrl, credentialsManager, state, imageManager, client, - dockerClient, _, _ := setup(t) + ctrl, credentialsManager, state, imageManager, client, dockerClient, _, _ := setup(t) defer ctrl.Finish() + ec2MetadataClient := mock_ec2.NewMockEC2MetadataClient(ctrl) mockCredentialsProvider := app_mocks.NewMockProvider(ctrl) mockMobyPlugins := mock_mobypkgwrapper.NewMockPlugins(ctrl) var discoverEndpointsInvoked sync.WaitGroup @@ -86,6 +86,7 @@ func TestDoStartHappyPath(t *testing.T) { }).Return("telemetry-endpoint", nil) client.EXPECT().DiscoverTelemetryEndpoint(gomock.Any()).Return( "tele-endpoint", nil).AnyTimes() + ec2MetadataClient.EXPECT().OutpostARN().Return("", nil) gomock.InOrder( mockCredentialsProvider.EXPECT().Retrieve().Return(credentials.Value{}, nil), @@ -94,7 +95,8 @@ func TestDoStartHappyPath(t *testing.T) { mockMobyPlugins.EXPECT().Scan().Return([]string{}, nil), dockerClient.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]string{}, nil), - client.EXPECT().RegisterContainerInstance(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return("arn", "", nil), + client.EXPECT().RegisterContainerInstance(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), + gomock.Any(), gomock.Any()).Return("arn", "", nil), imageManager.EXPECT().SetSaver(gomock.Any()), dockerClient.EXPECT().ContainerEvents(gomock.Any()).Return(containerChangeEvents, nil), state.EXPECT().AllImageStates().Return(nil), @@ -112,6 +114,7 @@ func TestDoStartHappyPath(t *testing.T) { dockerClient: dockerClient, terminationHandler: func(saver statemanager.Saver, taskEngine engine.TaskEngine) {}, mobyPlugins: mockMobyPlugins, + ec2MetadataClient: ec2MetadataClient, } var agentW sync.WaitGroup @@ -167,6 +170,7 @@ func TestDoStartTaskENIHappyPath(t *testing.T) { }).Return("telemetry-endpoint", nil) client.EXPECT().DiscoverTelemetryEndpoint(gomock.Any()).Return( "tele-endpoint", nil).AnyTimes() + mockMetadata.EXPECT().OutpostARN().Return("", nil) gomock.InOrder( mockOS.EXPECT().Getpid().Return(10), @@ -188,8 +192,10 @@ func TestDoStartTaskENIHappyPath(t *testing.T) { mockMobyPlugins.EXPECT().Scan().Return([]string{}, nil), dockerClient.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]string{}, nil), - client.EXPECT().RegisterContainerInstance(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Do( - func(x interface{}, attributes []*ecs.Attribute, y interface{}, z interface{}, w interface{}) { + client.EXPECT().RegisterContainerInstance(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), + gomock.Any(), gomock.Any()).Do( + func(x interface{}, attributes []*ecs.Attribute, y interface{}, z interface{}, w interface{}, + outpostARN interface{}) { vpcFound := false subnetFound := false for _, attribute := range attributes { @@ -522,10 +528,12 @@ func TestDoStartCgroupInitHappyPath(t *testing.T) { discoverEndpointsInvoked.Add(2) containerChangeEvents := make(chan dockerapi.DockerContainerChangeEvent) + ec2MetadataClient := mock_ec2.NewMockEC2MetadataClient(ctrl) dockerClient.EXPECT().Version(gomock.Any(), gomock.Any()).AnyTimes() dockerClient.EXPECT().SupportedVersions().Return(apiVersions) imageManager.EXPECT().StartImageCleanupProcess(gomock.Any()).MaxTimes(1) mockCredentialsProvider.EXPECT().IsExpired().Return(false).AnyTimes() + ec2MetadataClient.EXPECT().OutpostARN().Return("", nil) gomock.InOrder( mockControl.EXPECT().Init().Return(nil), @@ -535,7 +543,8 @@ func TestDoStartCgroupInitHappyPath(t *testing.T) { mockMobyPlugins.EXPECT().Scan().Return([]string{}, nil), dockerClient.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]string{}, nil), - client.EXPECT().RegisterContainerInstance(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return("arn", "", nil), + client.EXPECT().RegisterContainerInstance(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), + gomock.Any(), gomock.Any()).Return("arn", "", nil), imageManager.EXPECT().SetSaver(gomock.Any()), dockerClient.EXPECT().ContainerEvents(gomock.Any()).Return(containerChangeEvents, nil), state.EXPECT().AllImageStates().Return(nil), @@ -566,6 +575,7 @@ func TestDoStartCgroupInitHappyPath(t *testing.T) { dockerClient: dockerClient, terminationHandler: func(saver statemanager.Saver, taskEngine engine.TaskEngine) {}, mobyPlugins: mockMobyPlugins, + ec2MetadataClient: ec2MetadataClient, resourceFields: &taskresource.ResourceFields{ Control: mockControl, }, @@ -635,6 +645,8 @@ func TestDoStartGPUManagerHappyPath(t *testing.T) { mockCredentialsProvider := app_mocks.NewMockProvider(ctrl) mockGPUManager := mock_gpu.NewMockGPUManager(ctrl) mockMobyPlugins := mock_mobypkgwrapper.NewMockPlugins(ctrl) + ec2MetadataClient := mock_ec2.NewMockEC2MetadataClient(ctrl) + devices := []*ecs.PlatformDevice{ { Id: aws.String("id1"), @@ -657,6 +669,7 @@ func TestDoStartGPUManagerHappyPath(t *testing.T) { dockerClient.EXPECT().SupportedVersions().Return(apiVersions) imageManager.EXPECT().StartImageCleanupProcess(gomock.Any()).MaxTimes(1) mockCredentialsProvider.EXPECT().IsExpired().Return(false).AnyTimes() + ec2MetadataClient.EXPECT().OutpostARN().Return("", nil) gomock.InOrder( mockGPUManager.EXPECT().Initialize().Return(nil), @@ -668,7 +681,8 @@ func TestDoStartGPUManagerHappyPath(t *testing.T) { gomock.Any()).Return([]string{}, nil), mockGPUManager.EXPECT().GetDriverVersion().Return("396.44"), mockGPUManager.EXPECT().GetDevices().Return(devices), - client.EXPECT().RegisterContainerInstance(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), devices).Return("arn", "", nil), + client.EXPECT().RegisterContainerInstance(gomock.Any(), gomock.Any(), gomock.Any(), + gomock.Any(), devices, gomock.Any()).Return("arn", "", nil), imageManager.EXPECT().SetSaver(gomock.Any()), dockerClient.EXPECT().ContainerEvents(gomock.Any()).Return(containerChangeEvents, nil), state.EXPECT().AllImageStates().Return(nil), @@ -700,6 +714,7 @@ func TestDoStartGPUManagerHappyPath(t *testing.T) { dockerClient: dockerClient, terminationHandler: func(saver statemanager.Saver, taskEngine engine.TaskEngine) {}, mobyPlugins: mockMobyPlugins, + ec2MetadataClient: ec2MetadataClient, resourceFields: &taskresource.ResourceFields{ NvidiaGPUManager: mockGPUManager, }, diff --git a/agent/ec2/blackhole_ec2_metadata_client.go b/agent/ec2/blackhole_ec2_metadata_client.go index 05c51523981..a7ed6eb2fa1 100644 --- a/agent/ec2/blackhole_ec2_metadata_client.go +++ b/agent/ec2/blackhole_ec2_metadata_client.go @@ -80,3 +80,7 @@ func (blackholeMetadataClient) PublicIPv4Address() (string, error) { func (blackholeMetadataClient) SpotInstanceAction() (string, error) { return "", errors.New("blackholed") } + +func (blackholeMetadataClient) OutpostARN() (string, error) { + return "", errors.New("blackholed") +} diff --git a/agent/ec2/ec2_metadata_client.go b/agent/ec2/ec2_metadata_client.go index 5e37d610a4d..30f5074b270 100644 --- a/agent/ec2/ec2_metadata_client.go +++ b/agent/ec2/ec2_metadata_client.go @@ -37,6 +37,7 @@ const ( InstanceIDResource = "instance-id" PrivateIPv4Resource = "local-ipv4" PublicIPv4Resource = "public-ipv4" + OutpostARN = "outpost-arn" ) const ( @@ -78,6 +79,7 @@ type EC2MetadataClient interface { PrivateIPv4Address() (string, error) PublicIPv4Address() (string, error) SpotInstanceAction() (string, error) + OutpostARN() (string, error) } type ec2MetadataClientImpl struct { @@ -194,3 +196,7 @@ func (c *ec2MetadataClientImpl) PrivateIPv4Address() (string, error) { func (c *ec2MetadataClientImpl) SpotInstanceAction() (string, error) { return c.client.GetMetadata(SpotInstanceActionResource) } + +func (c *ec2MetadataClientImpl) OutpostARN() (string, error) { + return c.client.GetMetadata(OutpostARN) +} diff --git a/agent/ec2/mocks/ec2_mocks.go b/agent/ec2/mocks/ec2_mocks.go index 8ffa9430d16..4300b499589 100644 --- a/agent/ec2/mocks/ec2_mocks.go +++ b/agent/ec2/mocks/ec2_mocks.go @@ -156,6 +156,21 @@ func (mr *MockEC2MetadataClientMockRecorder) InstanceIdentityDocument() *gomock. return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstanceIdentityDocument", reflect.TypeOf((*MockEC2MetadataClient)(nil).InstanceIdentityDocument)) } +// OutpostARN mocks base method +func (m *MockEC2MetadataClient) OutpostARN() (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OutpostARN") + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// OutpostARN indicates an expected call of OutpostARN +func (mr *MockEC2MetadataClientMockRecorder) OutpostARN() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OutpostARN", reflect.TypeOf((*MockEC2MetadataClient)(nil).OutpostARN)) +} + // PrimaryENIMAC mocks base method func (m *MockEC2MetadataClient) PrimaryENIMAC() (string, error) { m.ctrl.T.Helper()