Skip to content
Merged
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
4 changes: 4 additions & 0 deletions aws_quickstart/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 4.19.1 (August 25, 2026)

- Fix Datadog Operator Marketplace agreement discovery and acceptance for Lambda runtimes that lack required agreement operations or paginators.

# 4.19.0 (August 21, 2026)

- Accept the free Datadog Operator AWS Marketplace agreement in the commercial AWS partition when EKS instrumentation is selected, allowing the managed add-on installation to proceed without Marketplace permissions on the Datadog integration role. GovCloud and China deployments skip automatic agreement acceptance.
Expand Down
4 changes: 3 additions & 1 deletion aws_quickstart/accept_operator_subscription.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import cfnresponse

from cfn_common import send_cfn_response

from marketplace_agreement_compat import apply_marketplace_agreement_compatibility

LOGGER = logging.getLogger()
LOGGER.setLevel(logging.INFO)
Expand Down Expand Up @@ -612,6 +612,7 @@ def wait_for_entitlement(
def ensure_subscription(event, *, deadline=None):
try:
session = boto3.Session()
compatibility_applied = apply_marketplace_agreement_compatibility(session)
discovery_client = session.client(
"marketplace-discovery",
region_name=MARKETPLACE_REGION,
Expand All @@ -634,6 +635,7 @@ def ensure_subscription(event, *, deadline=None):
"succeeded",
"clients_created",
boto3_version=getattr(boto3, "__version__", "unknown"),
marketplace_compatibility_model_applied=compatibility_applied,
)

agreement_id = find_active_agreement(agreement_client, deadline=deadline)
Expand Down
98 changes: 89 additions & 9 deletions aws_quickstart/accept_operator_subscription_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
validate_zero_charge_summary,
wait_for_entitlement,
)
from marketplace_agreement_compat import apply_marketplace_agreement_compatibility


def paginator_client(**operation_pages):
Expand Down Expand Up @@ -166,11 +167,88 @@ def test_release_embeds_subscription_source(self):

self.assertIn(
"embed_python_source_with_common datadog_integration_permissions.yaml "
"accept_operator_subscription.py ACCEPT_OPERATOR_SUBSCRIPTION_SOURCE",
"accept_operator_subscription.py ACCEPT_OPERATOR_SUBSCRIPTION_SOURCE "
"marketplace_agreement_compat.py",
release,
)


class TestMarketplaceAgreementCompatibility(unittest.TestCase):
def test_adds_missing_operations_and_paginators(self):
session = MagicMock()
runtime_shape = {"runtime": True}
service_data = {
"operations": {"SearchAgreements": {}},
"shapes": {"ResourceId": runtime_shape},
}
paginator_config = {}
session._session.get_service_data.return_value = service_data
session._session.get_paginator_model.return_value._paginator_config = (
paginator_config
)

applied = apply_marketplace_agreement_compatibility(session)

self.assertTrue(applied)
self.assertIn("CreateAgreementRequest", service_data["operations"])
self.assertIn("AcceptAgreementRequest", service_data["operations"])
self.assertIn("GetAgreementEntitlements", service_data["operations"])
self.assertIn("CreateAgreementRequestInput", service_data["shapes"])
self.assertIn("AcceptAgreementRequestOutput", service_data["shapes"])
self.assertIn("GetAgreementEntitlementsInput", service_data["shapes"])
self.assertIn("GetAgreementEntitlementsOutput", service_data["shapes"])
self.assertIs(service_data["shapes"]["ResourceId"], runtime_shape)
self.assertIn("GetAgreementEntitlements", paginator_config)
self.assertIn("SearchAgreements", paginator_config)

def test_preserves_runtime_model_when_definitions_are_available(self):
session = MagicMock()
operations = {
"CreateAgreementRequest": {"runtime": True},
"AcceptAgreementRequest": {"runtime": True},
"GetAgreementEntitlements": {"runtime": True},
}
paginator_config = {
"GetAgreementEntitlements": {"runtime": True},
"SearchAgreements": {"runtime": True},
}
service_data = {"operations": operations.copy(), "shapes": {}}
session._session.get_service_data.return_value = service_data
session._session.get_paginator_model.return_value._paginator_config = (
paginator_config.copy()
)

applied = apply_marketplace_agreement_compatibility(session)

self.assertFalse(applied)
self.assertEqual(service_data["operations"], operations)
self.assertEqual(service_data["shapes"], {})

def test_adds_only_missing_paginator_to_runtime_model(self):
session = MagicMock()
operations = {
"CreateAgreementRequest": {"runtime": True},
"AcceptAgreementRequest": {"runtime": True},
"GetAgreementEntitlements": {"runtime": True},
}
shapes = {"RuntimeShape": {"runtime": True}}
service_data = {"operations": operations.copy(), "shapes": shapes.copy()}
search_paginator = {"runtime": True}
paginator_config = {"SearchAgreements": search_paginator}
session._session.get_service_data.return_value = service_data
session._session.get_paginator_model.return_value._paginator_config = (
paginator_config
)

applied = apply_marketplace_agreement_compatibility(session)

self.assertTrue(applied)
self.assertEqual(service_data["operations"], operations)
self.assertEqual(service_data["shapes"], shapes)
self.assertIn("GetAgreementEntitlements", paginator_config)
self.assertIs(paginator_config["SearchAgreements"], search_paginator)


class TestAgreementDiscovery(unittest.TestCase):
def test_returns_active_agreement(self):
client = paginator_client(
Expand Down Expand Up @@ -200,15 +278,11 @@ def test_returns_none_when_no_active_agreement_exists(self):

self.assertIsNone(find_active_agreement(client))

def test_rejects_multiple_active_agreements(self):
def test_rejects_multiple_active_agreements_across_pages(self):
client = paginator_client(
search_agreements=[
{
"agreementViewSummaries": [
{"agreementId": "agreement-1"},
{"agreementId": "agreement-2"},
]
}
{"agreementViewSummaries": [{"agreementId": "agreement-1"}]},
{"agreementViewSummaries": [{"agreementId": "agreement-2"}]},
]
)

Expand Down Expand Up @@ -667,8 +741,14 @@ def test_request_acceptance_failure(self):


class TestClientInitialization(unittest.TestCase):
@patch(
"accept_operator_subscription.apply_marketplace_agreement_compatibility",
return_value=False,
)
@patch("accept_operator_subscription.boto3.Session")
def test_reports_runtime_without_marketplace_discovery(self, mock_session):
def test_reports_runtime_without_marketplace_discovery(
self, mock_session, _mock_compatibility
):
mock_session.return_value.client.side_effect = RuntimeError("UnknownServiceError")

with self.assertRaises(SubscriptionError) as raised:
Expand Down
Loading
Loading