Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: AWS S3 instrumentation #2112

Merged
merged 27 commits into from
Jun 24, 2021
Merged

feat: AWS S3 instrumentation #2112

merged 27 commits into from
Jun 24, 2021

Conversation

trentm
Copy link
Member

@trentm trentm commented Jun 16, 2021

Fixes: #1954

Note that this PR will only include aws-sdk@2 instrumentation. A separate PR will address instrumentation of @awk-sdk/client-s3 (aka "v3" or the "Modular AWS SDK for JavaScript").

Checklist

  • Implement code
  • Add tests
  • Update documentation
  • Add CHANGELOG.asciidoc entry
  • Commit message follows commit guidelines

@trentm trentm self-assigned this Jun 16, 2021
@github-actions github-actions bot added the agent-nodejs Make available for APM Agents project planning. label Jun 16, 2021
@trentm trentm force-pushed the trentm/instrument-s3 branch from 3ad0cb1 to ccc7fd7 Compare June 16, 2021 00:08
@apmmachine
Copy link
Contributor

apmmachine commented Jun 16, 2021

💚 Build Succeeded

the below badges are clickable and redirect to their specific view in the CI or DOCS
Pipeline View Test View Changes Artifacts preview

Expand to view the summary

Build stats

  • Build Cause: Pull request #2112 updated

  • Start Time: 2021-06-23T23:15:34.843+0000

  • Duration: 18 min 14 sec

  • Commit: ea9e8ed

Test stats 🧪

Test Results
Failed 0
Passed 19040
Skipped 0
Total 19040

Trends 🧪

Image of Build Times

Image of Tests

@trentm
Copy link
Member Author

trentm commented Jun 18, 2021

The state of instrumenting v3 of the JavaScript AWS SDK (https://github.com/aws/aws-sdk-js-v3/tree/main/clients/client-s3) is as follows. (See https://github.com/aws/aws-sdk-js-v3/tree/main/clients/client-s3#import for what I mean by the import styles.)

  1. We can get it to automatically instrument if the CommonJS (a.k.a. ES5) require-style is used to import it.
  2. We cannot automatically instrument if ESM (a.k.a. ES module, ES6+) import-style is used to import it. We cannot instrument it with known workarounds/hacks (e.g. this technique) because the package (@aws-sdk/client-s3) distributes separate source trees for CommonJS and ESM. (An import { ... } from "@aws-sdk/client-s3" and a const { ... } = require("@aws-sdk/client-s3") will load separate source files.)
  3. As a possible documented workaround, we can provide a manual mechanism for users of import { ... } from "@aws-sdk/client-s3" to instrument their created client. It would look like this:
import apm from 'elastic-apm-node/start.js'
import { S3Client, HeadObjectCommand } from "@aws-sdk/client-s3";

const s3client = new S3Client({ region: 'us-west-1' })
apm.instrumentAwsSdkClient(s3client)   // <--- this is the only new line

// ...

I'm not sure if that is worthwhile.

@trentm
Copy link
Member Author

trentm commented Jun 22, 2021

testing access points

S3 Access Points is a
separate AWS service that allows you to create a way to access a bucket
(or parts of a bucket) with policy separate from the bucket itself. It can
be useful for having multiple access policies for a single bucket. An access
point is tied to a specific S3 bucket and region. You then use the access
point ARN -- of the form
arn:aws:s3:$region:$accountId:accesspoint/$accesspointName -- instead of the
bucket name with the usual S3 client APIs, e.g.:

s3Client.getObject({
    Bucket: 'arn:aws:s3:us-west-1:123456789012:accesspoint/trentm-play-ap1',
    Key: 'aDir/aFile.txt'
}, function (err, data) {
    // ...
})

This comment documents my testing of the S3 instrumentation with Access Points.
It is not included in the test suite because, AFAIK, localstack doesn't support
access points.

First I created one to use:

% aws s3control create-access-point --account-id $accountId --bucket trentm-play-s3-bukkit2 --name trentm-play-ap1 --region us-west-1  # bucket is in us-west-1
% aws s3control list-access-points --account-id=$accountId --region=us-west-1
{
    "AccessPointList": [
        ...
        {
            "Name": "trentm-play-ap1",
            "NetworkOrigin": "Internet",
            "Bucket": "trentm-play-s3-bukkit2"
        }
    ]

In the v2 JavaScript AWS SDK, using an access point and the useArnRegion:true
config option for the client allows accessing a bucket in one region with a
client configured for a different region

With an access point the context.destination.address changes to a different
endpoint:

trentm-play-ap1-123456789012.s3-accesspoint.us-west-1.amazonaws.com
$accesspointName-$accountId.s3-accesspoint.$region.amazonaws.com

I used the following ARN in my dev script that exercises the S3 API a little bit.

const ARN1 = `arn:aws:s3:us-west-1:${accountId}:accesspoint/trentm-play-ap1`

A resulting span for a HeadObject call is:

    {
        "span": {
            "name": "S3 HeadObject accesspoint/trentm-play-ap1",
            "type": "storage",
            "subtype": "s3",
            "action": "HeadObject",
            "context": {
                "destination": {
                    "address": "trentm-play-ap1-123456789012.s3-accesspoint.us-west-1.amazonaws.com",
                    "port": 443,
                    "service": {
                        "name": "s3",
                        "type": "storage",
                        "resource": "accesspoint/trentm-play-ap1"
                    },
                    "cloud": {
                        "region": "us-west-1"
                    }
                }
            },
            "outcome": "success",
            // ...

@trentm trentm mentioned this pull request Jun 22, 2021
5 tasks
@@ -15,7 +15,7 @@ fi
# Skip for node v8 because it results in this warning:
# openssl config failed: error:25066067:DSO support routines:DLFCN_LOAD:could not load the shared library
if [[ $major_node_version -gt 8 ]]; then
export NODE_OPTIONS="${NODE_OPTIONS:+${NODE_OPTIONS}} --openssl-config=./test/openssl-config-for-testing.cnf"
export NODE_OPTIONS="${NODE_OPTIONS:+${NODE_OPTIONS}} --openssl-config=$(pwd)/test/openssl-config-for-testing.cnf"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REVIEW NOTE: This was necessary to avoid this error message:

openssl config failed: error:02001002:system library:fopen:No such file or directory

when executing a subprocess to run node fixtures/use-s3.js as part of s3.test.js below... because that subprocess is run in a separate directory (in "test/instrumentation/modules/aws-sdk") rather than at the top-level. Using an absolute path fixes this -- which is the same thing that is done for this in test/test.js:

args.unshift('--require', path.join(__dirname, '_promise_rejection.js'))

@@ -210,6 +213,8 @@ else
DOCKER_COMPOSE_FILE=docker-compose-all.yml
fi

ELASTIC_APM_ASYNC_HOOKS=${ELASTIC_APM_ASYNC_HOOKS:-true}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REVIEW NOTE: This ensures that ELASTIC_APM_ASYNC_HOOKS is either "true" or "false", and not "" or "false". When it is the empty string, things are fine, but the agent logs:

{"log.level":"warn","@timestamp":"2021-06-22T23:22:55.871Z","log":{"logger":"elastic-apm-node"},"ecs":{"version":"1.6.0"},"message":"unrecognized boolean value \"\" for \"asyncHooks\""}
{"log.level":"warn","@timestamp":"2021-06-22T23:22:55.872Z","log":{"logger":"elastic-apm-node"},"ecs":{"version":"1.6.0"},"message":"unrecognized boolean value \"\" for \"asyncHooks\""}

which is just noise in test output.

@trentm trentm marked this pull request as ready for review June 22, 2021 23:42
@trentm trentm requested a review from astorm June 22, 2021 23:42
@trentm
Copy link
Member Author

trentm commented Jun 22, 2021

@astorm I haven't yet added a changelog entry, but this is ready for review. Our AWS instrumentation might benefit from a separate documentation page, but I think that could be done in a separate issue.

@trentm
Copy link
Member Author

trentm commented Jun 23, 2021

That "Integration Tests failure" above (https://apm-ci.elastic.co/job/apm-agent-nodejs/job/apm-agent-nodejs-mbp/job/PR-2112/) has this in the log:

[2021-06-23T00:26:18.539Z] ERROR: for apm-server  Container "83e98b03806a" is unhealthy.
[2021-06-23T00:26:18.539Z] Encountered errors while bringing up the project.
[2021-06-23T00:26:18.539Z] Starting/Building stack services..
[2021-06-23T00:26:18.539Z] 
[2021-06-23T00:26:18.539Z] Traceback (most recent call last):
[2021-06-23T00:26:18.539Z]   File "scripts/compose.py", line 19, in <module>
[2021-06-23T00:26:18.539Z]     main()
[2021-06-23T00:26:18.539Z]   File "scripts/compose.py", line 15, in main
[2021-06-23T00:26:18.539Z]     setup()
[2021-06-23T00:26:18.539Z]   File "/var/lib/jenkins/workspace/ration-tests-selector-mbp_master/src/github.com/elastic/apm-integration-testing/scripts/modules/cli.py", line 204, in __call__
[2021-06-23T00:26:18.539Z]     self.args.func()
[2021-06-23T00:26:18.539Z]   File "/var/lib/jenkins/workspace/ration-tests-selector-mbp_master/src/github.com/elastic/apm-integration-testing/scripts/modules/cli.py", line 586, in start_handler
[2021-06-23T00:26:18.539Z]     self.build_start_handler("start")
[2021-06-23T00:26:18.540Z]   File "/var/lib/jenkins/workspace/ration-tests-selector-mbp_master/src/github.com/elastic/apm-integration-testing/scripts/modules/cli.py", line 732, in build_start_handler
[2021-06-23T00:26:18.540Z]     self.run_docker_compose_process(docker_compose_cmd + up_params)
[2021-06-23T00:26:18.540Z]   File "/var/lib/jenkins/workspace/ration-tests-selector-mbp_master/src/github.com/elastic/apm-integration-testing/scripts/modules/cli.py", line 472, in run_docker_compose_process
[2021-06-23T00:26:18.540Z]     subprocess.check_call(docker_compose_cmd)
[2021-06-23T00:26:18.540Z]   File "/usr/lib/python3.6/subprocess.py", line 311, in check_call
[2021-06-23T00:26:18.540Z]     raise CalledProcessError(retcode, cmd)
[2021-06-23T00:26:18.540Z] subprocess.CalledProcessError: Command '['docker-compose', '-f', '/var/lib/jenkins/workspace/ration-tests-selector-mbp_master/src/github.com/elastic/apm-integration-testing/docker-compose.yml', '--no-ansi', '--log-level', 'ERROR', 'up', '-d', '--quiet-pull']' returned non-zero exit status 1.

I don't know whta that is about. I'll try to run it again -> https://apm-ci.elastic.co/job/apm-integration-tests-selector-mbp/job/master/18016/

Copy link
Contributor

@astorm astorm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good.

Just to say it out loud I do have mixed feeling about incorporating another dependency (localstack) directly into our CI ... but I think I'm slightly in favor of it if it can get us out of the business of mocking requests (especially with the specre of a new SDK with different requests to mock out)

Review is just some due diligence style questions and some nits. Trending towards approval once those questions are answered. 👍

test/script/local-deps-start.sh Outdated Show resolved Hide resolved
lib/instrumentation/modules/aws-sdk/s3.js Show resolved Hide resolved
package.json Show resolved Hide resolved
lib/instrumentation/modules/aws-sdk.js Show resolved Hide resolved
lib/instrumentation/modules/aws-sdk/s3.js Outdated Show resolved Hide resolved
lib/instrumentation/modules/aws-sdk/s3.js Show resolved Hide resolved
@trentm trentm requested a review from astorm June 23, 2021 23:16
Copy link
Contributor

@astorm astorm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@trentm trentm merged commit 9ece910 into master Jun 24, 2021
@trentm trentm deleted the trentm/instrument-s3 branch June 24, 2021 23:19
dgieselaar pushed a commit to dgieselaar/apm-agent-nodejs that referenced this pull request Sep 10, 2021
Note that this only includes 'aws-sdk@2' instrumentation. Instrumentation
of '@awk-sdk/client-s3' (aka "v3" or the "Modular AWS SDK for JavaScript")
will be done in a separate change.

This adds localstack to the test suite for testing the S3 API.

Fixes: elastic#1954
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
agent-nodejs Make available for APM Agents project planning.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[META 408] Instrumentation for AWS S3
3 participants