Skip to content

Commit

Permalink
Add scrapping ECS_CONTAINER_METADATA_URI_V4 for ECS (#453)
Browse files Browse the repository at this point in the history
* Add metadata point v4 and delete run in aws

* Add log and delete flag

* Add some interface and add final endpoint v4

* Fix some typo and add interface

* Fix typo

* Delete apply interface

* Delete interface and debug

* Delete Ecs Util instance variable

* Add back ecsUtilInstance

* Add type assertion

* Delete type assertion

* Add type assertion again

* Delete type assertion

* Fix typo and nitpick

* Add back mode EC2

* Add runinAws

* Add type assertion

* Add type assertion

* delete type interface

* Add log for validating

* change to parse ecs region

* Build back image

* Revert back to original

* Add back strings

* Add parseClusterName

* Parse the cluster

* Delete parse cluster

* Delete go proxy

* Fix testing
  • Loading branch information
khanhntd authored May 3, 2022
1 parent 11f1c75 commit ad9c25b
Show file tree
Hide file tree
Showing 7 changed files with 34 additions and 30 deletions.
2 changes: 1 addition & 1 deletion cmd/config-downloader/downloader.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ func main() {
outputDir,
func(path string, info os.FileInfo, err error) error {
if err != nil {
fmt.Printf("Cannot access %v: %v", path, err)
fmt.Printf("Cannot access %v: %v \n", path, err)
return err
}
if info.IsDir() {
Expand Down
1 change: 1 addition & 0 deletions plugins/processors/ecsdecorator/ecsinfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ func (e *ecsInfo) getMemReserved() int64 {
func newECSInfo(hostIP string) (e *ecsInfo) {
e = &ecsInfo{hostIP: hostIP, refreshInterval: 1 * time.Minute, shutdownC: make(chan bool), httpClient: httpclient.New()}
containerInstance := e.getContainerInstanceInfo()
//Sample Cluster Name: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-agent-introspection.html
e.clusterName = containerInstance.Cluster
e.containerInstanceId = e.getContainerInstanceIdFromArn(containerInstance.ContainerInstanceArn)
e.cgroup = newCGroupScannerForContainer()
Expand Down
2 changes: 1 addition & 1 deletion translator/cmdutil/translatorutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ func GenerateMergedJsonConfigMap(ctx *context.Context) (map[string]interface{},
ctx.InputJsonDirPath(),
func(path string, info os.FileInfo, err error) error {
if err != nil {
fmt.Printf("Cannot access %v: %v", path, err)
fmt.Printf("Cannot access %v: %v \n", path, err)
return err
}
if info.Mode()&os.ModeSymlink != 0 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func (d *LogGroupName) ApplyRule(input interface{}) (string, interface{}) {

if context.CurrentContext().RunInContainer() {
if ecsutil.GetECSUtilSingleton().IsECS() {
clusterName := util.GetECSClusterNameFromEnv()
clusterName := ecsutil.GetECSUtilSingleton().Cluster
if clusterName != "" {
lgName = fmt.Sprintf(ECSLogGroupNameFormat, clusterName)
}
Expand Down
16 changes: 1 addition & 15 deletions translator/translate/logs/util/get_ecs_cluster_name.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
package util

import (
"strings"

"github.com/aws/amazon-cloudwatch-agent/translator/util/ecsutil"
)

Expand All @@ -17,19 +15,7 @@ func GetECSClusterName(sectionKey string, input map[string]interface{}) string {
}

if clusterName == "" {
clusterName = GetECSClusterNameFromEnv()
}
return clusterName
}

func GetECSClusterNameFromEnv() string {
var clusterName string
if ecsutil.GetECSUtilSingleton().IsECS() {
clusterName = ecsutil.GetECSUtilSingleton().Cluster
res := strings.Split(clusterName, "/")
if len(res) > 0 {
clusterName = res[len(res)-1]
}
}
return clusterName
}
}
33 changes: 25 additions & 8 deletions translator/util/ecsutil/ecsutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
const (
v2MetadataEndpoint = "http://169.254.170.2/v2/metadata"
v3MetadataEndpointEnv = "ECS_CONTAINER_METADATA_URI"
v4MetadataEndpointEnv = "ECS_CONTAINER_METADATA_URI_V4"
)

type ecsMetadataResponse struct {
Expand All @@ -32,6 +33,7 @@ type ecsUtil struct {
}

var ecsUtilInstance *ecsUtil

var ecsUtilOnce sync.Once

func GetECSUtilSingleton() *ecsUtil {
Expand All @@ -48,13 +50,14 @@ func initECSUtilSingleton() (newInstance *ecsUtil) {
}
log.Println("I! attempt to access ECS task metadata to determine whether I'm running in ECS.")
ecsMetadataResponse, err := newInstance.getECSMetadata()

if err != nil {
log.Printf("I! access ECS task metadata fail with response %v, assuming I'm not running in ECS.\n", err)
return
}

newInstance.parseRegion(ecsMetadataResponse)
newInstance.Cluster = ecsMetadataResponse.Cluster
newInstance.parseClusterName(ecsMetadataResponse)
newInstance.TaskARN = ecsMetadataResponse.TaskARN
return

Expand All @@ -65,26 +68,29 @@ func (e *ecsUtil) IsECS() bool {
}

func (e *ecsUtil) getECSMetadata() (em *ecsMetadataResponse, err error) {
// choose available endpoint
if v3MetadataEndpoint, ok := os.LookupEnv(v3MetadataEndpointEnv); !ok {
em, err = e.getMetadataResponse(v2MetadataEndpoint)
} else {
// Based on endpoint to get ECS metadata, for more information on the respond, https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-metadata-endpoint.html
if v4MetadataEndpoint, ok := os.LookupEnv(v4MetadataEndpointEnv); ok {
em, err = e.getMetadataResponse(v4MetadataEndpoint + "/task")
} else if v3MetadataEndpoint, ok := os.LookupEnv(v3MetadataEndpointEnv); ok {
em, err = e.getMetadataResponse(v3MetadataEndpoint + "/task")
} else {
em, err = e.getMetadataResponse(v2MetadataEndpoint)
}
return
}

func (e *ecsUtil) getMetadataResponse(endpoint string) (em *ecsMetadataResponse, err error) {
em = &ecsMetadataResponse{}
resp, err := e.httpClient.Request(endpoint)

if err != nil {
return
}

err = json.Unmarshal(resp, em)
if err != nil {
log.Printf("E! unable to parse resp from ecsmetadata endpoint, error: %v", err)
log.Printf("D! resp content is %s", string(resp))
log.Printf("E! Unable to parse response from ecsmetadata endpoint, error: %v", err)
log.Printf("D! Content is %s", string(resp))
}
return
}
Expand All @@ -97,7 +103,18 @@ func (e *ecsUtil) parseRegion(em *ecsMetadataResponse) {
splitedContent := strings.Split(em.TaskARN, ":")
// When splitting the ARN with ":", the 4th segment is the region
if len(splitedContent) < 4 {
log.Printf("E! invalid ecs task arn: %s", em.TaskARN)
log.Printf("E! Invalid ecs task arn: %s", em.TaskARN)
}
e.Region = splitedContent[3]
}

// There is only one format for ClusterArn (https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_Cluster.html)
// arn:aws:ecs:region:aws_account_id:cluster/cluster-name
func (e *ecsUtil) parseClusterName(em *ecsMetadataResponse) {
splitedContent := strings.Split(em.Cluster, "/")
// When splitting the ClusterName with /, the last is always the cluster name
if len(splitedContent) == 0 {
log.Printf("E! Invalid cluster arn: %s", em.Cluster)
}
e.Cluster = splitedContent[len(splitedContent)-1]
}
8 changes: 4 additions & 4 deletions translator/util/sdkutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (
"github.com/aws/amazon-cloudwatch-agent/translator/config"
"github.com/aws/amazon-cloudwatch-agent/translator/util/ec2util"
"github.com/aws/amazon-cloudwatch-agent/translator/util/ecsutil"

"github.com/aws/aws-sdk-go/aws/session"
)

Expand All @@ -36,7 +35,7 @@ func DetectAgentMode(configuredMode string) string {
fmt.Println("I! Detected from ENV instance is EC2")
return config.ModeEC2
}

if defaultEC2Region() != "" {
fmt.Println("I! Detected the instance is EC2")
return config.ModeEC2
Expand Down Expand Up @@ -93,15 +92,16 @@ func detectRegion(mode string, credsConfig map[string]string) (region string) {

// For ec2, fallback to metadata when no region info found in credential profile.
if region == "" && mode == config.ModeEC2 {
fmt.Println("I! Trying to detect region from ec2")
region = defaultEC2Region()
}

// try to get region from ecs metadata
if region == "" && mode == config.ModeEC2 {
fmt.Println("I! detect region from ecs")
fmt.Println("I! Trying to detect region from ecs")
region = defaultECSRegion()
}

return
}

Expand Down

0 comments on commit ad9c25b

Please sign in to comment.