Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .autover/changes/f13d1778-21ba-4438-b4d5-aecbc524e11c.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"Projects": [
{
"Name": "Amazon.Lambda.Core",
"Type": "Minor",
"ChangelogMessages": [
"Add ILambdaContext.W3C to expose the W3C trace-context fields (traceparent, tracestate, baggage) carried on clientContext.w3c at invoke time."
]
},
{
"Name": "Amazon.Lambda.RuntimeSupport",
"Type": "Minor",
"ChangelogMessages": [
"Implement ILambdaContext.W3C in LambdaContext, surfacing the allowlisted W3C trace-context fields (traceparent, tracestate, baggage) parsed from the client context header."
]
},
{
"Name": "Amazon.Lambda.TestUtilities",
"Type": "Minor",
"ChangelogMessages": [
"Add W3C trace-context support to TestLambdaContext via the settable W3CFields property and the W3C property."
]
},
{
"Name": "Amazon.Lambda.AspNetCoreServer",
"Type": "Minor",
"ChangelogMessages": [
"Implement ILambdaContext.W3C on the SnapStart empty context, returning an empty trace-context during initialization."
]
}
]
}
46 changes: 46 additions & 0 deletions .github/workflows/dockerized-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: dockerized-test

permissions:
contents: read

on:
push:
branches: [master]
pull_request:
branches: ['*']
workflow_dispatch:

jobs:
dockerized-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Set up .NET
uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
dotnet-version: |
10.0.x

- name: Publish W3CTestHandler
run: |
dotnet publish test/dockerized/W3CTestHandler/W3CTestHandler.csproj \
-c Release \
-r linux-x64 \
--self-contained \
-o test/dockerized/tasks
chmod +x test/dockerized/tasks/bootstrap

- name: Build the test image
run: |
docker build . \
-t local/test \
-f Dockerfile.test \
--build-arg BASE_IMAGE=public.ecr.aws/lambda/provided:al2023

- name: Run dockerized suites
uses: aws/containerized-test-runner-for-aws-lambda@0863dd17b5fc19585250a2405c0f939a77b4f397 # main
with:
suiteFileArray: '["./test/dockerized/suites/*.json"]'
dockerImageName: 'local/test'
taskFolder: './test/dockerized/tasks'
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,5 @@ global.json

# JetBrains Rider per-project cache
**/*.lscache

test/dockerized/tasks/
16 changes: 16 additions & 0 deletions Dockerfile.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

ARG BASE_IMAGE=public.ecr.aws/lambda/provided:al2023
FROM ${BASE_IMAGE}


ARG RIE_URL=https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie

RUN curl -fsSL -o /usr/local/bin/aws-lambda-rie "${RIE_URL}" \
&& chmod +x /usr/local/bin/aws-lambda-rie

COPY test/dockerized/tasks /var/task
RUN chmod +x /var/task/bootstrap

ENTRYPOINT ["/usr/local/bin/aws-lambda-rie", "/var/task/bootstrap"]
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Amazon.Lambda.Core;

namespace Amazon.Lambda.AspNetCoreServer.Internal;
Expand Down Expand Up @@ -64,4 +65,8 @@ public SnapStartEmptyLambdaContext()
public IClientApplication Client { get; }
public IDictionary<string, string> Custom { get; } = new Dictionary<string, string>();
public string TenantId { get; }

private static readonly IReadOnlyDictionary<string, string> EmptyW3C =
new ReadOnlyDictionary<string, string>(new Dictionary<string, string>());
public IReadOnlyDictionary<string, string> W3C => EmptyW3C;
}
10 changes: 10 additions & 0 deletions Libraries/src/Amazon.Lambda.Core/ILambdaContext.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
namespace Amazon.Lambda.Core
{
using System;
using System.Collections.Generic;

/// <summary>
/// Object that allows you to access useful information available within
Expand Down Expand Up @@ -107,6 +108,15 @@ public interface ILambdaContext
/// handlers).
/// </summary>
ILambdaSerializer Serializer { get { return null; } }

/// <summary>
/// The W3C trace-context fields (<c>traceparent</c>, <c>tracestate</c>,
/// <c>baggage</c>) carried on the invoke's <c>clientContext.w3c</c> payload.
/// </summary>
IReadOnlyDictionary<string, string> W3C
{
get { return new System.Collections.ObjectModel.ReadOnlyDictionary<string, string>(new Dictionary<string, string>()); }
}
#endif
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

using Amazon.Lambda.Core;
using System;
using System.Collections.Generic;
using Amazon.Lambda.RuntimeSupport.Helpers;

namespace Amazon.Lambda.RuntimeSupport
Expand All @@ -30,6 +31,7 @@ internal class LambdaContext : ILambdaContext
private readonly int _memoryLimitInMB;
private readonly Lazy<CognitoIdentity> _cognitoIdentityLazy;
private readonly Lazy<CognitoClientContext> _cognitoClientContextLazy;
private readonly Lazy<IReadOnlyDictionary<string, string>> _w3cLazy;
private readonly IConsoleLoggerWriter _consoleLogger;

public LambdaContext(RuntimeApiHeaders runtimeApiHeaders, LambdaEnvironment lambdaEnvironment, IConsoleLoggerWriter consoleLogger)
Expand All @@ -49,6 +51,7 @@ public LambdaContext(RuntimeApiHeaders runtimeApiHeaders, LambdaEnvironment lamb
long.TryParse(_runtimeApiHeaders.DeadlineMs, out _deadlineMs);
_cognitoIdentityLazy = new Lazy<CognitoIdentity>(() => CognitoIdentity.FromJson(runtimeApiHeaders.CognitoIdentityJson));
_cognitoClientContextLazy = new Lazy<CognitoClientContext>(() => CognitoClientContext.FromJson(runtimeApiHeaders.ClientContextJson));
_w3cLazy = new Lazy<IReadOnlyDictionary<string, string>>(() => W3CTraceContext.FromClientContextJson(runtimeApiHeaders.ClientContextJson));
}

public string TraceId => _runtimeApiHeaders.TraceId;
Expand Down Expand Up @@ -77,6 +80,8 @@ public LambdaContext(RuntimeApiHeaders runtimeApiHeaders, LambdaEnvironment lamb

public string TenantId => _runtimeApiHeaders.TenantId;

public IReadOnlyDictionary<string, string> W3C => _w3cLazy.Value;

/// <summary>
/// The serializer the Lambda function registered with the runtime, surfaced via
/// <see cref="ILambdaContext.Serializer"/>. Assigned per-invocation by
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text.Json;

namespace Amazon.Lambda.RuntimeSupport
{
/// <summary>
/// Extracts the W3C trace-context fields (traceparent, tracestate, baggage)
/// carried on <c>clientContext.w3c</c> at invoke time. Any other key on
/// <c>w3c</c> is ignored, and any allowlisted key whose value is not a
/// string is dropped.
/// </summary>
internal static class W3CTraceContext
{
internal static readonly string[] AllowedFields = { "traceparent", "tracestate", "baggage" };

private static readonly IReadOnlyDictionary<string, string> Empty =
new ReadOnlyDictionary<string, string>(new Dictionary<string, string>());

internal static IReadOnlyDictionary<string, string> FromClientContextJson(string clientContextJson)
{
if (string.IsNullOrWhiteSpace(clientContextJson))
{
return Empty;
}

JsonDocument doc;
try
{
doc = JsonDocument.Parse(clientContextJson);
}
catch (JsonException)
{
return Empty;
}

using (doc)
{
var root = doc.RootElement;
if (root.ValueKind != JsonValueKind.Object)
{
return Empty;
}

if (!root.TryGetProperty("w3c", out var w3c))
{
return Empty;
}

if (w3c.ValueKind != JsonValueKind.Object)
{
return Empty;
}

var fields = new Dictionary<string, string>(AllowedFields.Length);
foreach (var key in AllowedFields)
{
if (!w3c.TryGetProperty(key, out var value))
{
continue;
}
// Allowlisted keys whose value is not a JSON string are dropped.
if (value.ValueKind != JsonValueKind.String)
{
continue;
}
fields[key] = value.GetString();
}

return new ReadOnlyDictionary<string, string>(fields);
}
}
}
}
25 changes: 25 additions & 0 deletions Libraries/src/Amazon.Lambda.TestUtilities/TestLambdaContext.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;

Expand Down Expand Up @@ -87,5 +88,29 @@ public class TestLambdaContext : ILambdaContext
/// in production.
/// </summary>
public ILambdaSerializer Serializer { get; set; }

/// <summary>
/// The W3C trace-context fields (<c>traceparent</c>, <c>tracestate</c>,
/// <c>baggage</c>) a test wants to pretend were carried on
/// <c>clientContext.w3c</c> at invoke time.
/// </summary>
public IDictionary<string, string> W3CFields { get; set; }

/// <summary>
/// The W3C trace-context fields configured via <see cref="W3CFields"/>,
/// wrapped in a read-only dictionary. Returns an empty read-only dictionary
/// when no fields were set.
/// </summary>
public IReadOnlyDictionary<string, string> W3C
{
get
{
if (W3CFields == null)
{
return new ReadOnlyDictionary<string, string>(new Dictionary<string, string>());
}
return new ReadOnlyDictionary<string, string>(new Dictionary<string, string>(W3CFields));
}
}
}
}
Loading
Loading