From 77d0cea8dcbd5a3f520c1eb56098259814890688 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Mon, 28 Oct 2024 19:15:51 +0200 Subject: [PATCH 1/2] Use OpenTelemetry OCI S3 bucket for coredump testing --- .../workflows/unit-test-on-pull-request.yml | 8 +++ tools/coredump/coredump_test.go | 64 ++++++++++--------- tools/coredump/main.go | 29 ++++++++- tools/coredump/modulestore/store.go | 32 ++++++---- .../testdata/amd64/graalvm-native.json | 2 +- .../testdata/amd64/perl528bking.13.json | 25 -------- .../testdata/amd64/perl534.220234.json | 2 +- .../amd64/python310.stringbench.20086.json | 2 +- .../testdata/amd64/python311.50282.json | 2 +- .../testdata/amd64/ruby30.253432.json | 2 +- 10 files changed, 91 insertions(+), 77 deletions(-) delete mode 100644 tools/coredump/testdata/amd64/perl528bking.13.json diff --git a/.github/workflows/unit-test-on-pull-request.yml b/.github/workflows/unit-test-on-pull-request.yml index 5a2b4ec6..8810bf96 100644 --- a/.github/workflows/unit-test-on-pull-request.yml +++ b/.github/workflows/unit-test-on-pull-request.yml @@ -56,6 +56,14 @@ jobs: uses: actions/checkout@v4 - name: Set up environment uses: ./.github/workflows/env + - name: Cache coredump modules + uses: actions/cache@v4 + with: + path: tools/coredump/modulecache + key: coredumps-${{ matrix.target_arch }}-${{ hashFiles('tools/coredump/testdata/${{ matrix.target_arch }}/*.json') }} + restore-keys: | + coredumps-${{ matrix.target_arch }} + coredumps- - name: Tests run: make test TARGET_ARCH=${{ matrix.target_arch }} diff --git a/tools/coredump/coredump_test.go b/tools/coredump/coredump_test.go index ef0c1e3b..26bbde68 100644 --- a/tools/coredump/coredump_test.go +++ b/tools/coredump/coredump_test.go @@ -3,33 +3,37 @@ package main -// NOTE: temporarily disabled until we figured out how to best do this without S3 in the OTel env - -//nolint:gocritic -//func TestCoreDumps(t *testing.T) { -// cases, err := findTestCases(true) -// require.NoError(t, err) -// require.NotEmpty(t, cases) -// -// store, err := initModuleStore() -// require.NoError(t, err) -// -// for _, filename := range cases { -// filename := filename -// t.Run(filename, func(t *testing.T) { -// testCase, err := readTestCase(filename) -// require.NoError(t, err) -// -// ctx := context.Background() -// -// core, err := OpenStoreCoredump(store, testCase.CoredumpRef, testCase.Modules) -// require.NoError(t, err) -// defer core.Close() -// -// data, err := ExtractTraces(ctx, core, false, nil) -// -// require.NoError(t, err) -// require.Equal(t, testCase.Threads, data) -// }) -// } -//} +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestCoreDumps(t *testing.T) { + cases, err := findTestCases(true) + require.NoError(t, err) + require.NotEmpty(t, cases) + + store, err := initModuleStore() + require.NoError(t, err) + + for _, filename := range cases { + filename := filename + t.Run(filename, func(t *testing.T) { + testCase, err := readTestCase(filename) + require.NoError(t, err) + + ctx := context.Background() + + core, err := OpenStoreCoredump(store, testCase.CoredumpRef, testCase.Modules) + require.NoError(t, err) + defer core.Close() + + data, err := ExtractTraces(ctx, core, false, nil) + + require.NoError(t, err) + require.Equal(t, testCase.Threads, data) + }) + } +} diff --git a/tools/coredump/main.go b/tools/coredump/main.go index 173cb2ec..d24aeb37 100644 --- a/tools/coredump/main.go +++ b/tools/coredump/main.go @@ -11,8 +11,10 @@ import ( "context" "errors" "flag" + "fmt" "os" + "github.com/aws/aws-sdk-go-v2/aws" awsconfig "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/s3" @@ -21,8 +23,19 @@ import ( "go.opentelemetry.io/ebpf-profiler/tools/coredump/modulestore" ) +// moduleStoreRegion defines the S3 bucket OCI region. +const moduleStoreRegion = "us-sanjose-1" + +// moduleStoreObjectNamespace defines the S3 bucket OCI object name space. +const moduleStoreObjectNamespace = "axtwf1hkrwcy" + +// modulePublicReadUrl defines the S3 bucket OCI public read only base path. +// +//nolint:lll +const modulePublicReadURL = "sm-wftyyzHJkBghWeexmK1o5ArimNwZC-5eBej5Lx4e46sLVHtO_y7Zf7FZgoIu_/n/axtwf1hkrwcy" + // moduleStoreS3Bucket defines the S3 bucket used for the module store. -const moduleStoreS3Bucket = "optimyze-proc-mem-testdata" +const moduleStoreS3Bucket = "ebpf-profiling-coredumps" func main() { log.SetReportCaller(false) @@ -59,10 +72,20 @@ func main() { } func initModuleStore() (*modulestore.Store, error) { + publicReadURL := fmt.Sprintf("https://%s.objectstorage.%s.oci.customer-oci.com/p/%s/b/%s/o/", + moduleStoreObjectNamespace, moduleStoreRegion, modulePublicReadURL, moduleStoreS3Bucket) + cfg, err := awsconfig.LoadDefaultConfig(context.Background()) if err != nil { return nil, err } - s3Client := s3.NewFromConfig(cfg) - return modulestore.New(s3Client, moduleStoreS3Bucket, "modulecache") + + s3Client := s3.NewFromConfig(cfg, func(o *s3.Options) { + baseEndpoint := fmt.Sprintf("https://%s.compat.objectstorage.%s.oraclecloud.com/", + moduleStoreObjectNamespace, moduleStoreRegion) + o.Region = moduleStoreRegion + o.BaseEndpoint = aws.String(baseEndpoint) + o.UsePathStyle = true + }) + return modulestore.New(s3Client, publicReadURL, moduleStoreS3Bucket, "modulecache") } diff --git a/tools/coredump/modulestore/store.go b/tools/coredump/modulestore/store.go index b169f469..35ac81dd 100644 --- a/tools/coredump/modulestore/store.go +++ b/tools/coredump/modulestore/store.go @@ -11,13 +11,13 @@ import ( "errors" "fmt" "io" + "net/http" "os" "path" "strings" "syscall" "time" - s3manager "github.com/aws/aws-sdk-go-v2/feature/s3/manager" "github.com/aws/aws-sdk-go-v2/service/s3" s3types "github.com/aws/aws-sdk-go-v2/service/s3/types" @@ -53,18 +53,27 @@ const ( // at the same time, also when created within multiple different applications. type Store struct { s3client *s3.Client + httpClient *http.Client + publicReadURL string bucket string localCachePath string } // New creates a new module storage. The modules present in the local cache are inspected and a // full index of the modules in the remote S3 bucket is retrieved and cached as well. -func New(s3client *s3.Client, s3Bucket, localCachePath string) (*Store, error) { +func New(s3client *s3.Client, publicReadURL, s3Bucket, localCachePath string) (*Store, error) { if err := os.MkdirAll(localCachePath, 0o750); err != nil { return nil, err } + tr := &http.Transport{ + MaxIdleConns: 2, + IdleConnTimeout: 30 * time.Second, + DisableCompression: true, + } return &Store{ s3client: s3client, + httpClient: &http.Client{Transport: tr}, + publicReadURL: publicReadURL, bucket: s3Bucket, localCachePath: localCachePath, }, nil @@ -179,7 +188,7 @@ func (store *Store) UploadModule(id ID) error { return fmt.Errorf("failed to check whether the module exists locally: %w", err) } if !present { - return fmt.Errorf("the given module `%s` isn't present locally", id) + return fmt.Errorf("the given module `%x` isn't present locally", id) } localPath := store.makeLocalPath(id) @@ -425,18 +434,13 @@ func (store *Store) ensurePresentLocally(id ID) (string, error) { defer file.Close() moduleKey := makeS3Key(id) - req := &s3.GetObjectInput{ - Bucket: &store.bucket, - Key: &moduleKey, - } - - downloader := s3manager.NewDownloader(store.s3client) - _, err = downloader.Download(context.TODO(), file, req) + resp, err := http.Get(store.publicReadURL + moduleKey) if err != nil { - if isErrNoSuchKey(err) { - return "", errors.New("module doesn't exist in remote storage") - } - return "", fmt.Errorf("failed to download file from S3: %w", err) + return "", fmt.Errorf("failed to request file: %w", err) + } + defer resp.Body.Close() + if _, err = io.Copy(file, resp.Body); err != nil { + return "", fmt.Errorf("failed to receive file: %w", err) } if err = commitTempFile(file, localPath); err != nil { diff --git a/tools/coredump/testdata/amd64/graalvm-native.json b/tools/coredump/testdata/amd64/graalvm-native.json index 88231581..a4d106c0 100644 --- a/tools/coredump/testdata/amd64/graalvm-native.json +++ b/tools/coredump/testdata/amd64/graalvm-native.json @@ -1,5 +1,5 @@ { - "coredump-ref": "a9c4a72d50d0c9fa133b3d39756405ba431cfe329e39b3f9dd28ab9cbd256076", + "coredump-ref": "e7fa60d8b9eddd1a29c2aeea9b21ef625fa3ad1559e37a5433958620c9841f1f", "threads": [ { "lwp": 3327417, diff --git a/tools/coredump/testdata/amd64/perl528bking.13.json b/tools/coredump/testdata/amd64/perl528bking.13.json deleted file mode 100644 index 20a93361..00000000 --- a/tools/coredump/testdata/amd64/perl528bking.13.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "coredump-ref": "5fb536eb8fdcbd55af9a9a256a876e60b0801ddb1f75614570b6b77eec18dcf2", - "threads": [ - { - "lwp": 13, - "frames": [ - "libpthread-2.17.so+0xe6e0", - "libperl.so+0x1688b6", - "libperl.so+0x168956", - "libperl.so+0x1651ed", - "libperl.so+0x165d5b", - "libperl.so+0x13e63a", - "libperl.so+0xe3cd7", - "HelloWorld::print+0 in hi.pl:12", - "+0 in hi.pl:19", - "libperl.so+0xe0af2", - "libperl.so+0x6913e", - "perl+0x400d1a", - "libc-2.17.so+0x22554", - "perl+0x400d52" - ] - } - ], - "modules": null -} diff --git a/tools/coredump/testdata/amd64/perl534.220234.json b/tools/coredump/testdata/amd64/perl534.220234.json index eee68556..3a4b9108 100644 --- a/tools/coredump/testdata/amd64/perl534.220234.json +++ b/tools/coredump/testdata/amd64/perl534.220234.json @@ -1,5 +1,5 @@ { - "coredump-ref": "d7fa9bf0effe15fd628f1cfa50a2e2d22c574f2c3e8e794f248b34c6b0e6fc66", + "coredump-ref": "682732701a4de336b4e9fcfd25caaf963d918ce8b5e554afeb001e63d956bd86", "threads": [ { "lwp": 220234, diff --git a/tools/coredump/testdata/amd64/python310.stringbench.20086.json b/tools/coredump/testdata/amd64/python310.stringbench.20086.json index f8367d6d..e1fd0287 100644 --- a/tools/coredump/testdata/amd64/python310.stringbench.20086.json +++ b/tools/coredump/testdata/amd64/python310.stringbench.20086.json @@ -1,5 +1,5 @@ { - "coredump-ref": "94a9c5cd6295d08274ff0c4f513a0157b220675c252753e2bd7598f3d4017dde", + "coredump-ref": "caf74bc49055cd6959fe96a6c14b19da025254b2351293a1b9d1b9165d78074e", "threads": [ { "lwp": 20086, diff --git a/tools/coredump/testdata/amd64/python311.50282.json b/tools/coredump/testdata/amd64/python311.50282.json index 35521371..d453dbd2 100644 --- a/tools/coredump/testdata/amd64/python311.50282.json +++ b/tools/coredump/testdata/amd64/python311.50282.json @@ -1,5 +1,5 @@ { - "coredump-ref": "07b722f7560748f27cb9f7bc5822a3054f817e60c44a36b77f51a1e9ad3875bc", + "coredump-ref": "2d15786c1581bb1e069be0d12cd50b3de99532951d85668a1961c6a35cdd3542", "threads": [ { "lwp": 50282, diff --git a/tools/coredump/testdata/amd64/ruby30.253432.json b/tools/coredump/testdata/amd64/ruby30.253432.json index 08e59ee8..437217b4 100644 --- a/tools/coredump/testdata/amd64/ruby30.253432.json +++ b/tools/coredump/testdata/amd64/ruby30.253432.json @@ -1,5 +1,5 @@ { - "coredump-ref": "ff1183a2679a72cdd32b3963af31bbf0aa3067c6e713cd02e6722015673e0633", + "coredump-ref": "1b496ac7c0747b896e6c5ef5720db01d900a224a529eb74d5ce0c787a7e4bcd1", "threads": [ { "lwp": 253432, From 2269e6e9e3e9b27b10bf8bae10e35903354323b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Wed, 30 Oct 2024 21:19:42 +0200 Subject: [PATCH 2/2] Fix hashFiles to calculate the json files the expansion is not done inside the literal string --- .github/workflows/unit-test-on-pull-request.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/unit-test-on-pull-request.yml b/.github/workflows/unit-test-on-pull-request.yml index 8810bf96..253078cc 100644 --- a/.github/workflows/unit-test-on-pull-request.yml +++ b/.github/workflows/unit-test-on-pull-request.yml @@ -60,7 +60,7 @@ jobs: uses: actions/cache@v4 with: path: tools/coredump/modulecache - key: coredumps-${{ matrix.target_arch }}-${{ hashFiles('tools/coredump/testdata/${{ matrix.target_arch }}/*.json') }} + key: coredumps-${{ matrix.target_arch }}-${{ hashFiles('tools/coredump/testdata/*/*.json') }} restore-keys: | coredumps-${{ matrix.target_arch }} coredumps-