Skip to content
This repository was archived by the owner on Mar 23, 2026. It is now read-only.
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
9 changes: 6 additions & 3 deletions localstack-core/localstack/aws/catalog_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def __init__(self, message: str, error_code: int):


class ServiceOrOperationNotSupportedException(AwsServiceAvailabilityException):
def __init__(self, service_name: str, operation_name: str):
def __init__(self, service_name: str, operation_name: str | None = None):
if operation_name is None:
message = f"Sorry, the {service_name} service is not currently supported by LocalStack."
error_code = 3
Expand Down Expand Up @@ -53,13 +53,16 @@ def get_service_availability_exception(
status: AwsServicesSupportInLatest | AwsServiceOperationsSupportInLatest | None,
) -> AwsServiceAvailabilityException:
match status:
case AwsServicesSupportInLatest.SUPPORTED | AwsServiceOperationsSupportInLatest.SUPPORTED:
case AwsServicesSupportInLatest.SUPPORTED:
return LatestVersionRequiredException(service_name)
case AwsServiceOperationsSupportInLatest.SUPPORTED:
return LatestVersionRequiredException(service_name, operation_name)
case (
AwsServicesSupportInLatest.SUPPORTED_WITH_LICENSE_UPGRADE
| AwsServiceOperationsSupportInLatest.SUPPORTED_WITH_LICENSE_UPGRADE
| AwsServiceSupportAtRuntime.AVAILABLE_WITH_LICENSE_UPGRADE
):
return LicenseUpgradeRequiredException(service_name)
case AwsServiceOperationsSupportInLatest.SUPPORTED_WITH_LICENSE_UPGRADE:
return LicenseUpgradeRequiredException(service_name, operation_name)
case AwsServicesSupportInLatest.NOT_SUPPORTED | AwsServiceSupportAtRuntime.NOT_IMPLEMENTED:
return ServiceOrOperationNotSupportedException(service_name, operation_name)
Expand Down
2 changes: 2 additions & 0 deletions localstack-core/localstack/aws/handlers/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class PluginNotIncludedInUserLicenseError(NotImplementedError):
pass
25 changes: 11 additions & 14 deletions localstack-core/localstack/aws/handlers/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
from typing import Any

from botocore.model import OperationModel, ServiceModel
from plux.core.plugin import PluginDisabled

from localstack import config
from localstack.http import Response
Expand All @@ -22,6 +21,7 @@
from ..protocol.serializer import create_serializer
from ..protocol.service_router import determine_aws_protocol, determine_aws_service_model
from ..skeleton import Skeleton, create_skeleton
from .exceptions import PluginNotIncludedInUserLicenseError

LOG = logging.getLogger(__name__)

Expand Down Expand Up @@ -197,9 +197,15 @@ def create_exception_response(self, exception: Exception, context: RequestContex
message = exception_message
error = CommonServiceException("InternalFailure", message, status_code=501)
else:
service_status = get_aws_catalog().get_aws_service_status(
service_name, operation_name
)
catalog = get_aws_catalog()
if isinstance(exception, PluginNotIncludedInUserLicenseError):
# Operation name is provided when a plugin fails to load, although it is not relevant.
# In such cases, we should return an error without the operation name
service_status = catalog.get_aws_service_status(
service_name, operation_name=None
)
else:
service_status = catalog.get_aws_service_status(service_name, operation_name)
error = get_service_availability_exception(
service_name, operation_name, service_status
)
Expand Down Expand Up @@ -242,16 +248,7 @@ def create_exception_response(self, exception: Exception, context: RequestContex
operation = context.service.operation_model(context.service.operation_names[0])
msg = f"exception while calling {service_name} with unknown operation: {message}"

# Check for license restricted plugin message and set status code to 501
Comment thread
k-a-il marked this conversation as resolved.
if (
isinstance(exception, PluginDisabled)
and "not part of the active license agreement"
in str(getattr(exception, "reason", "")).lower()
):
status_code = 501
msg = f"exception while calling {service_name}.{operation.name}: {str(getattr(exception, 'reason', ''))}"
else:
status_code = 501 if config.FAIL_FAST else 500
status_code = 501 if config.FAIL_FAST else 500

error = CommonServiceException(
"InternalError", msg, status_code=status_code
Expand Down
14 changes: 10 additions & 4 deletions localstack-core/localstack/aws/handlers/service_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import logging
import threading

from plux import PluginDisabled

from localstack.http import Response
from localstack.services.plugins import Service, ServiceManager
from localstack.utils.sync import SynchronizedDefaultDict
Expand All @@ -11,7 +13,7 @@
from ..api import RequestContext
from ..chain import Handler, HandlerChain
from ..protocol.service_router import determine_aws_service_model_for_data_plane
from .service import ServiceRequestRouter
from .service import PluginNotIncludedInUserLicenseError, ServiceRequestRouter

LOG = logging.getLogger(__name__)

Expand Down Expand Up @@ -51,9 +53,13 @@ def require_service(self, _: HandlerChain, context: RequestContext, response: Re
)

request_router = self.service_request_router

# Ensure the Service is loaded and set to ServiceState.RUNNING if not in an erroneous state.
service_plugin: Service = self.service_manager.require(service_name)
try:
# Ensure the Service is loaded and set to ServiceState.RUNNING if not in an erroneous state.
service_plugin: Service = self.service_manager.require(service_name)
except PluginDisabled as e:
if e.reason == "This feature is not part of the active license agreement":
raise PluginNotIncludedInUserLicenseError()
raise

with self.service_locks[context.service.service_name]:
# try again to avoid race conditions
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/aws/handlers/test_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ class TestServiceExceptionSerializer:
[
(
AwsServiceSupportAtRuntime.AVAILABLE_WITH_LICENSE_UPGRADE,
"is not supported with your LocalStack license",
"is not included within your LocalStack license",
),
(
None,
Expand Down
Loading