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
1 change: 1 addition & 0 deletions aws-replicator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ If you wish to access the deprecated instructions, they can be found [here](http

## Change Log

* `0.1.25`: Fix dynamodb proxying for read-only mode.
* `0.1.24`: Fix healthcheck probe for proxy container
* `0.1.23`: Fix unpinned React.js dependencies preventing webui from loading
* `0.1.22`: Fix auth-related imports that prevent the AWS proxy from starting
Expand Down
7 changes: 7 additions & 0 deletions aws-replicator/aws_replicator/server/aws_request_forwarder.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,13 @@ def _is_read_request(self, context: RequestContext) -> bool:
# service-specific rules
if context.service.service_name == "cognito-idp" and operation_name == "InitiateAuth":
return True
if context.service.service_name == "dynamodb" and operation_name in {
"Scan",
"Query",
"BatchGetItem",
"PartiQLSelect",
}:
return True
# TODO: add more rules
return False

Expand Down
2 changes: 1 addition & 1 deletion aws-replicator/setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = localstack-extension-aws-replicator
version = 0.1.24
version = 0.1.25
summary = LocalStack AWS Proxy Extension
description = Proxy AWS resources into your LocalStack instance
long_description = file: README.md
Expand Down
80 changes: 80 additions & 0 deletions aws-replicator/tests/test_proxy_requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
from botocore.exceptions import ClientError
from localstack.aws.connect import connect_to
from localstack.utils.aws.arns import sqs_queue_arn, sqs_queue_url_for_arn
from localstack.utils.aws.resources import create_dynamodb_table
from localstack.utils.net import wait_for_port_open
from localstack.utils.strings import short_uid
from localstack.utils.sync import retry

from aws_replicator.client.auth_proxy import start_aws_auth_proxy
Expand Down Expand Up @@ -243,3 +245,81 @@ def test_sqs_requests(start_aws_proxy, cleanups):
"Attributes"
]["QueueArn"]
assert result == queue_arn_aws


class TestDynamoDBRequests:
region_name = "us-east-1"

@pytest.fixture(scope="class")
def dynamodb_client_aws(self):
return boto3.client("dynamodb", region_name=self.region_name)

@pytest.fixture
def create_dynamodb_table_aws(self, dynamodb_client_aws):
tables = []

def factory(**kwargs):
kwargs["client"] = dynamodb_client_aws
if "table_name" not in kwargs:
kwargs["table_name"] = f"test-table-{short_uid()}"
if "partition_key" not in kwargs:
kwargs["partition_key"] = "id"

tables.append(kwargs["table_name"])

return create_dynamodb_table(**kwargs)

yield factory

# cleanup
for table in tables:
try:
dynamodb_client_aws.delete_table(TableName=table)
except Exception as e:
print(f"error cleaning up table {table}: {e}", table, e)

def test_dynamodb_requests_read_only(
self, start_aws_proxy, create_dynamodb_table_aws, dynamodb_client_aws
):
# create clients
dynamodb_client = connect_to(region_name=self.region_name).dynamodb

# start proxy - only forwarding requests for read operations
config = ProxyConfig(
services={"dynamodb": {"resources": ".*", "read_only": True}},
bind_host=PROXY_BIND_HOST,
)
start_aws_proxy(config)

# create table in AWS
table_name = f"test-table-{short_uid()}"
create_dynamodb_table_aws(table_name=table_name)
tables_aws = dynamodb_client_aws.list_tables()["TableNames"]
assert table_name in tables_aws

# assert that local call for this table is proxied
tables_local = dynamodb_client.list_tables()["TableNames"]
assert table_name in tables_local

item = {"id": {"S": "123"}, "value": {"S": "foobar"}}
# put item via AWS client
dynamodb_client_aws.put_item(TableName=table_name, Item=item)

# get item via AWS client
result = dynamodb_client_aws.get_item(TableName=table_name, Key={"id": {"S": "123"}})
assert result["Item"] == item

# get item via local client
result = dynamodb_client.get_item(TableName=table_name, Key={"id": {"S": "123"}})
assert result["Item"] == item

# assert that scan operation is working
result = dynamodb_client.scan(TableName=table_name)
assert len(result["Items"]) == 1

# assert that write operation is NOT working - it's sent to localstack, which cannot find the table
item3 = {"id": {"S": "789"}, "value": {"S": "foobar3"}}
with pytest.raises(ClientError) as exc:
dynamodb_client.put_item(TableName=table_name, Item=item3)

assert exc.match("ResourceNotFoundException")