Skip to content

Commit 80bc76d

Browse files
committed
extracting containerId from fargate
1 parent 6d95d70 commit 80bc76d

File tree

2 files changed

+130
-6
lines changed

2 files changed

+130
-6
lines changed

pkg/host/info.go

Lines changed: 75 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@ import (
99
"bufio"
1010
"bytes"
1111
"context"
12+
"encoding/json"
1213
"errors"
1314
"fmt"
1415
"io"
16+
"net/http"
1517
"os"
1618
"regexp"
1719
"strings"
@@ -31,6 +33,8 @@ const (
3133
mountInfoLocation = "/proc/self/mountinfo"
3234
osReleaseLocation = "/etc/os-release"
3335

36+
ecsMetadataEnvV4 = "ECS_CONTAINER_METADATA_URI_V4"
37+
3438
k8sKind = "kubepods"
3539
docker = "docker"
3640
containerd = "containerd"
@@ -112,7 +116,20 @@ func (i *Info) IsContainer() (bool, error) {
112116
}
113117
}
114118

115-
return containsContainerReference(i.selfCgroupLocation)
119+
ref, err := containsContainerReference(i.selfCgroupLocation)
120+
if ref {
121+
return true, nil
122+
}
123+
124+
if os.Getenv(ecsMetadataEnvV4) != "" {
125+
return true, nil
126+
}
127+
128+
if err != nil {
129+
return false, err
130+
}
131+
132+
return false, nil
116133
}
117134

118135
// ResourceID returns a unique identifier for the resource.
@@ -121,7 +138,7 @@ func (i *Info) IsContainer() (bool, error) {
121138
func (i *Info) ResourceID(ctx context.Context) (string, error) {
122139
isContainer, _ := i.IsContainer()
123140
if isContainer {
124-
return i.containerID()
141+
return i.containerID(ctx)
125142
}
126143

127144
return i.hostID(ctx)
@@ -134,7 +151,7 @@ func (i *Info) ContainerInfo(ctx context.Context) (*v1.Resource_ContainerInfo, e
134151
if err != nil {
135152
return nil, err
136153
}
137-
containerId, err := i.containerID()
154+
containerId, err := i.containerID(ctx)
138155
if err != nil {
139156
return nil, err
140157
}
@@ -203,9 +220,34 @@ func (i *Info) releaseInfo(ctx context.Context, osReleaseLocation string) (*v1.R
203220
}
204221

205222
// containerID returns the container ID of the current running environment.
206-
func (i *Info) containerID() (string, error) {
207-
containerID, err := containerIDFromMountInfo(i.mountInfoLocation)
208-
return uuid.NewMD5(uuid.NameSpaceDNS, []byte(containerID)).String(), err
223+
func (i *Info) containerID(ctx context.Context) (string, error) {
224+
var (
225+
containerIDMount string
226+
errMount error
227+
)
228+
229+
containerIDMount, errMount = containerIDFromMountInfo(i.mountInfoLocation)
230+
if containerIDMount != "" {
231+
return uuid.NewMD5(uuid.NameSpaceDNS, []byte(containerIDMount)).String(), nil
232+
}
233+
234+
if metadataURI := os.Getenv(ecsMetadataEnvV4); metadataURI != "" {
235+
if cid, errEcs := i.containerIDFromECS(ctx, metadataURI); errEcs == nil && cid != "" {
236+
return uuid.NewMD5(uuid.NameSpaceDNS, []byte(cid)).String(), nil
237+
} else if errEcs != nil {
238+
if errMount != nil {
239+
return "", errMount
240+
}
241+
242+
return "", errEcs
243+
}
244+
}
245+
246+
if errMount != nil {
247+
return "", errMount
248+
}
249+
250+
return "", errors.New("container ID not found")
209251
}
210252

211253
// containsContainerReference checks if the cgroup file contains references to container runtimes.
@@ -367,3 +409,30 @@ func mergeHostAndOsReleaseInfo(
367409
Id: osReleaseInfo[id],
368410
}
369411
}
412+
413+
func (i *Info) containerIDFromECS(ctx context.Context, uri string) (string, error) {
414+
req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil)
415+
if err != nil {
416+
return "", err
417+
}
418+
419+
resp, err := http.DefaultClient.Do(req)
420+
if err != nil {
421+
return "", err
422+
}
423+
defer resp.Body.Close()
424+
425+
if resp.StatusCode != http.StatusOK {
426+
return "", fmt.Errorf("metadata endpoint returned status %d", resp.StatusCode)
427+
}
428+
429+
var metadata struct {
430+
DockerId string `json:"DockerId"`
431+
}
432+
433+
if err = json.NewDecoder(resp.Body).Decode(&metadata); err != nil {
434+
return "", err
435+
}
436+
437+
return metadata.DockerId, nil
438+
}

pkg/host/info_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ package host
77

88
import (
99
"context"
10+
"fmt"
11+
"net/http"
12+
"net/http/httptest"
1013
"os"
1114
"strings"
1215
"testing"
@@ -633,3 +636,55 @@ func TestInfo_ParseOsReleaseFile(t *testing.T) {
633636
})
634637
}
635638
}
639+
640+
func TestInfo_containerIDFromECS(t *testing.T) {
641+
ctx := context.Background()
642+
643+
tests := []struct {
644+
name string
645+
handler http.HandlerFunc
646+
wantID string
647+
expectErr bool
648+
}{
649+
{
650+
name: "Test 1: success - valid JSON",
651+
handler: func(w http.ResponseWriter, r *http.Request) {
652+
w.WriteHeader(http.StatusOK)
653+
fmt.Fprintln(w, `{"DockerId":"c1234567890"}`)
654+
},
655+
wantID: "c1234567890",
656+
expectErr: false,
657+
},
658+
{
659+
name: "Test 2: non-200 response",
660+
handler: func(w http.ResponseWriter, r *http.Request) {
661+
w.WriteHeader(http.StatusInternalServerError)
662+
},
663+
expectErr: true,
664+
},
665+
{
666+
name: "Test 3: invalid JSON",
667+
handler: func(w http.ResponseWriter, r *http.Request) {
668+
w.WriteHeader(http.StatusOK)
669+
fmt.Fprintln(w, `not-a-json`)
670+
},
671+
expectErr: true,
672+
},
673+
}
674+
675+
for _, tt := range tests {
676+
t.Run(tt.name, func(t *testing.T) {
677+
srv := httptest.NewServer(tt.handler)
678+
defer srv.Close()
679+
680+
info := NewInfo()
681+
id, err := info.containerIDFromECS(ctx, srv.URL)
682+
if tt.expectErr {
683+
require.Error(t, err)
684+
} else {
685+
require.NoError(t, err)
686+
assert.Equal(t, tt.wantID, id)
687+
}
688+
})
689+
}
690+
}

0 commit comments

Comments
 (0)