Skip to content

Commit

Permalink
[WIP] Implement aws.ecs.* resource attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
Michele Mancioppi committed Aug 4, 2022
1 parent 14077a9 commit 411bb51
Show file tree
Hide file tree
Showing 4 changed files with 244 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
import os
import socket

from urllib.request import Request, urlopen

from opentelemetry.sdk.resources import Resource, ResourceDetector
from opentelemetry.semconv.resource import (
CloudPlatformValues,
Expand Down Expand Up @@ -58,13 +60,44 @@ def detect(self) -> "Resource":
"Failed to get container ID on ECS: %s.", exception
)

return Resource(
base_resource = Resource(
{
ResourceAttributes.CLOUD_PROVIDER: CloudProviderValues.AWS.value,
ResourceAttributes.CLOUD_PLATFORM: CloudPlatformValues.AWS_ECS.value,
ResourceAttributes.CONTAINER_NAME: socket.gethostname(),
ResourceAttributes.CONTAINER_ID: container_id,
}
)

metadata_endpoint = os.environ.get("ECS_CONTAINER_METADATA_URI_V4")

if not metadata_endpoint:
return base_resource

# Returns https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-metadata-endpoint-v4.html#task-metadata-endpoint-v4-response
metadata_container = _http_get(metadata_endpoint)
metadata_task = _http_get(f"{metadata_endpoint}/task")

task_arn = metadata_task["TaskARN"]
base_arn = task_arn[0 : task_arn.rindex(":")] # noqa
cluster: str = metadata_task["Cluster"]
cluster_arn = (
cluster if cluster.startswith("arn:") else f"{base_arn}:cluster/{cluster}"
)

return base_resource.merge(
Resource(
{
ResourceAttributes.AWS_ECS_CLUSTER_ARN: cluster_arn,
ResourceAttributes.AWS_ECS_CONTAINER_ARN: metadata_container[
"ContainerARN"
],
ResourceAttributes.AWS_ECS_LAUNCHTYPE: metadata_task["LaunchType"],
ResourceAttributes.AWS_ECS_TASK_ARN: task_arn,
ResourceAttributes.AWS_ECS_TASK_FAMILY: metadata_task["Family"],
ResourceAttributes.AWS_ECS_TASK_REVISION: metadata_task["Revision"],
}
)
)
# pylint: disable=broad-except
except Exception as exception:
Expand All @@ -73,3 +106,10 @@ def detect(self) -> "Resource":

logger.warning("%s failed: %s", self.__class__.__name__, exception)
return Resource.get_empty()

def _http_get(url):
with urlopen(
Request(url, method="GET"),
timeout=5,
) as response:
return response.read().decode("utf-8")
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"DockerId": "ea32192c8553fbff06c9340478a2ff089b2bb5646fb718b4ee206641c9086d66",
"Name": "curl",
"DockerName": "ecs-curltest-24-curl-cca48e8dcadd97805600",
"Image": "111122223333.dkr.ecr.us-west-2.amazonaws.com/curltest:latest",
"ImageID": "sha256:d691691e9652791a60114e67b365688d20d19940dde7c4736ea30e660d8d3553",
"Labels": {
"com.amazonaws.ecs.cluster": "default",
"com.amazonaws.ecs.container-name": "curl",
"com.amazonaws.ecs.task-arn": "arn:aws:ecs:us-west-2:111122223333:task/default/8f03e41243824aea923aca126495f665",
"com.amazonaws.ecs.task-definition-family": "curltest",
"com.amazonaws.ecs.task-definition-version": "24"
},
"DesiredStatus": "RUNNING",
"KnownStatus": "RUNNING",
"Limits": {
"CPU": 10,
"Memory": 128
},
"CreatedAt": "2020-10-02T00:15:07.620912337Z",
"StartedAt": "2020-10-02T00:15:08.062559351Z",
"Type": "NORMAL",
"LogDriver": "awslogs",
"LogOptions": {
"awslogs-create-group": "true",
"awslogs-group": "/ecs/metadata",
"awslogs-region": "us-west-2",
"awslogs-stream": "ecs/curl/8f03e41243824aea923aca126495f665"
},
"ContainerARN": "arn:aws:ecs:us-west-2:111122223333:container/0206b271-b33f-47ab-86c6-a0ba208a70a9",
"Networks": [
{
"NetworkMode": "awsvpc",
"IPv4Addresses": [
"10.0.2.100"
],
"AttachmentIndex": 0,
"MACAddress": "0e:9e:32:c7:48:85",
"IPv4SubnetCIDRBlock": "10.0.2.0/24",
"PrivateDNSName": "ip-10-0-2-100.us-west-2.compute.internal",
"SubnetGatewayIpv4Address": "10.0.2.1/24"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
{
"Cluster": "default",
"TaskARN": "arn:aws:ecs:us-west-2:111122223333:task/default/158d1c8083dd49d6b527399fd6414f5c",
"Family": "curltest",
"Revision": "26",
"DesiredStatus": "RUNNING",
"KnownStatus": "RUNNING",
"PullStartedAt": "2020-10-02T00:43:06.202617438Z",
"PullStoppedAt": "2020-10-02T00:43:06.31288465Z",
"AvailabilityZone": "us-west-2d",
"LaunchType": "EC2",
"Containers": [
{
"DockerId": "598cba581fe3f939459eaba1e071d5c93bb2c49b7d1ba7db6bb19deeb70d8e38",
"Name": "~internal~ecs~pause",
"DockerName": "ecs-curltest-26-internalecspause-e292d586b6f9dade4a00",
"Image": "amazon/amazon-ecs-pause:0.1.0",
"ImageID": "",
"Labels": {
"com.amazonaws.ecs.cluster": "default",
"com.amazonaws.ecs.container-name": "~internal~ecs~pause",
"com.amazonaws.ecs.task-arn": "arn:aws:ecs:us-west-2:111122223333:task/default/158d1c8083dd49d6b527399fd6414f5c",
"com.amazonaws.ecs.task-definition-family": "curltest",
"com.amazonaws.ecs.task-definition-version": "26"
},
"DesiredStatus": "RESOURCES_PROVISIONED",
"KnownStatus": "RESOURCES_PROVISIONED",
"Limits": {
"CPU": 0,
"Memory": 0
},
"CreatedAt": "2020-10-02T00:43:05.602352471Z",
"StartedAt": "2020-10-02T00:43:06.076707576Z",
"Type": "CNI_PAUSE",
"Networks": [
{
"NetworkMode": "awsvpc",
"IPv4Addresses": [
"10.0.2.61"
],
"AttachmentIndex": 0,
"MACAddress": "0e:10:e2:01:bd:91",
"IPv4SubnetCIDRBlock": "10.0.2.0/24",
"PrivateDNSName": "ip-10-0-2-61.us-west-2.compute.internal",
"SubnetGatewayIpv4Address": "10.0.2.1/24"
}
]
},
{
"DockerId": "ee08638adaaf009d78c248913f629e38299471d45fe7dc944d1039077e3424ca",
"Name": "curl",
"DockerName": "ecs-curltest-26-curl-a0e7dba5aca6d8cb2e00",
"Image": "111122223333.dkr.ecr.us-west-2.amazonaws.com/curltest:latest",
"ImageID": "sha256:d691691e9652791a60114e67b365688d20d19940dde7c4736ea30e660d8d3553",
"Labels": {
"com.amazonaws.ecs.cluster": "default",
"com.amazonaws.ecs.container-name": "curl",
"com.amazonaws.ecs.task-arn": "arn:aws:ecs:us-west-2:111122223333:task/default/158d1c8083dd49d6b527399fd6414f5c",
"com.amazonaws.ecs.task-definition-family": "curltest",
"com.amazonaws.ecs.task-definition-version": "26"
},
"DesiredStatus": "RUNNING",
"KnownStatus": "RUNNING",
"Limits": {
"CPU": 10,
"Memory": 128
},
"CreatedAt": "2020-10-02T00:43:06.326590752Z",
"StartedAt": "2020-10-02T00:43:06.767535449Z",
"Type": "NORMAL",
"LogDriver": "awslogs",
"LogOptions": {
"awslogs-create-group": "true",
"awslogs-group": "/ecs/metadata",
"awslogs-region": "us-west-2",
"awslogs-stream": "ecs/curl/158d1c8083dd49d6b527399fd6414f5c"
},
"ContainerARN": "arn:aws:ecs:us-west-2:111122223333:container/abb51bdd-11b4-467f-8f6c-adcfe1fe059d",
"Networks": [
{
"NetworkMode": "awsvpc",
"IPv4Addresses": [
"10.0.2.61"
],
"AttachmentIndex": 0,
"MACAddress": "0e:10:e2:01:bd:91",
"IPv4SubnetCIDRBlock": "10.0.2.0/24",
"PrivateDNSName": "ip-10-0-2-61.us-west-2.compute.internal",
"SubnetGatewayIpv4Address": "10.0.2.1/24"
}
]
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import unittest
from collections import OrderedDict
from unittest.mock import mock_open, patch
Expand All @@ -31,6 +32,11 @@
}


def _read_file(filename: str) -> str:
with open(os.path.join(os.path.dirname(__file__), filename)) as f:
return f.read()


class AwsEcsResourceDetectorTest(unittest.TestCase):
@patch.dict(
"os.environ",
Expand Down Expand Up @@ -60,8 +66,66 @@ class AwsEcsResourceDetectorTest(unittest.TestCase):
1:cpuset:/docker/bogusContainerIdThatShouldNotBeOneSetBecauseTheFirstOneWasPicked
""",
)
def test_simple_create(self, mock_open_function, mock_socket_gethostname):
def test_simple_create_metadata_v3(self, mock_open_function, mock_socket_gethostname):
actual = AwsEcsResourceDetector().detect()
self.assertDictEqual(
actual.attributes.copy(), OrderedDict(MockEcsResourceAttributes)
)

@patch.dict(
"os.environ",
{"ECS_CONTAINER_METADATA_URI_V4": "mock-uri-4"},
clear=True,
)
@patch(
"socket.gethostname",
return_value=f"{MockEcsResourceAttributes[ResourceAttributes.CONTAINER_NAME]}",
)
@patch(
"opentelemetry.sdk.extension.aws.resource.ecs._http_get",
)
@patch(
"mock-uri-4/task",
return_value=_read_file("metadatav4-response-task.json"),
)
@patch(
"builtins.open",
new_callable=mock_open,
read_data=f"""14:name=systemd:/docker/{MockEcsResourceAttributes[ResourceAttributes.CONTAINER_ID]}
13:rdma:/
12:pids:/docker/bogusContainerIdThatShouldNotBeOneSetBecauseTheFirstOneWasPicked
11:hugetlb:/docker/bogusContainerIdThatShouldNotBeOneSetBecauseTheFirstOneWasPicked
10:net_prio:/docker/bogusContainerIdThatShouldNotBeOneSetBecauseTheFirstOneWasPicked
9:perf_event:/docker/bogusContainerIdThatShouldNotBeOneSetBecauseTheFirstOneWasPicked
8:net_cls:/docker/bogusContainerIdThatShouldNotBeOneSetBecauseTheFirstOneWasPicked
7:freezer:/docker/
6:devices:/docker/bogusContainerIdThatShouldNotBeOneSetBecauseTheFirstOneWasPicked
5:memory:/docker/bogusContainerIdThatShouldNotBeOneSetBecauseTheFirstOneWasPicked
4:blkio:/docker/bogusContainerIdThatShouldNotBeOneSetBecauseTheFirstOneWasPicked
3:cpuacct:/docker/bogusContainerIdThatShouldNotBeOneSetBecauseTheFirstOneWasPicked
2:cpu:/docker/bogusContainerIdThatShouldNotBeOneSetBecauseTheFirstOneWasPicked
1:cpuset:/docker/bogusContainerIdThatShouldNotBeOneSetBecauseTheFirstOneWasPicked
""",
)
def test_simple_create_metadata_v4(self, mock_http_get_function, mock_open_function, mock_socket_gethostname):
def http_get_function(url, *args, **kwargs):
if url == "mock-uri-4":
return _read_file("metadatav4-response-container.json")
if url == "mock-uri-4/task":
return _read_file("metadatav4-response-task.json")

mock_http_get_function.side_effect = http_get_function

actual = AwsEcsResourceDetector().detect()
self.assertDictEqual(
actual.attributes.copy(),
OrderedDict({
**MockEcsResourceAttributes,
ResourceAttributes.AWS_ECS_CONTAINER_ARN: "arn:aws:ecs:us-west-2:111122223333:container/0206b271-b33f-47ab-86c6-a0ba208a70a9",
ResourceAttributes.AWS_ECS_CLUSTER_ARN: "arn:aws:ecs:us-west-2:111122223333:cluster/default",
ResourceAttributes.AWS_ECS_LAUNCHTYPE: "EC2",
ResourceAttributes.AWS_ECS_TASK_ARN: "arn:aws:ecs:us-west-2:111122223333:task/default/158d1c8083dd49d6b527399fd6414f5c",
ResourceAttributes.AWS_ECS_TASK_FAMILY: "curltest",
ResourceAttributes.AWS_ECS_TASK_REVISION: "26",
})
)

0 comments on commit 411bb51

Please sign in to comment.