mirror of
https://github.com/hanzoai/datastore.git
synced 2026-09-26 13:55:07 +00:00
231 lines
8.8 KiB
Python
231 lines
8.8 KiB
Python
import logging
|
|
import os
|
|
|
|
import pytest
|
|
|
|
import helpers.client
|
|
from helpers.cluster import ClickHouseCluster
|
|
from helpers.config_cluster import minio_secret_key
|
|
from helpers.mock_servers import start_mock_servers
|
|
|
|
|
|
def run_s3_mocks(started_cluster, args=[]):
|
|
script_dir = os.path.join(os.path.dirname(__file__), "s3_mocks")
|
|
start_mock_servers(
|
|
started_cluster,
|
|
script_dir,
|
|
[("mock_sts.py", "sts.amazonaws.com", "80", args)],
|
|
)
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def started_cluster():
|
|
try:
|
|
cluster = ClickHouseCluster(__file__)
|
|
cluster.add_instance(
|
|
"s3_with_environment_credentials",
|
|
with_minio=True,
|
|
env_variables={
|
|
"AWS_ACCESS_KEY_ID": "aws",
|
|
"AWS_SECRET_ACCESS_KEY": "aws123",
|
|
},
|
|
main_configs=[
|
|
"configs/use_environment_credentials.xml",
|
|
"configs/remote_servers_test_shared_localhost.xml",
|
|
"configs/named_collections.xml",
|
|
"configs/s3_credentials_provider_cache_size.xml",
|
|
],
|
|
user_configs=[
|
|
"configs/users.xml",
|
|
"configs/sync_insert.xml",
|
|
"configs/allow_server_credentials.xml",
|
|
],
|
|
)
|
|
|
|
sts = cluster.add_instance(
|
|
name="sts.amazonaws.com",
|
|
hostname="sts.amazonaws.com",
|
|
image="clickhouse/python-bottle",
|
|
tag="latest",
|
|
stay_alive=True,
|
|
)
|
|
sts.stop_clickhouse(kill=True)
|
|
|
|
logging.info("Starting cluster...")
|
|
cluster.start()
|
|
logging.info("Cluster started")
|
|
|
|
logging.info("S3 bucket created")
|
|
run_s3_mocks(cluster)
|
|
|
|
yield cluster
|
|
finally:
|
|
cluster.shutdown()
|
|
|
|
|
|
def test_sts_smoke(started_cluster):
|
|
instance = started_cluster.instances["s3_with_environment_credentials"]
|
|
|
|
instance.query(
|
|
f"""
|
|
INSERT INTO FUNCTION s3('http://{started_cluster.minio_host}:{started_cluster.minio_port}/{started_cluster.minio_bucket}/test_sts_smoke.csv', 'minio', '{minio_secret_key}')
|
|
SELECT number, number * 10, number * 100 FROM numbers(10) SETTINGS s3_truncate_on_insert = 1"""
|
|
)
|
|
|
|
with pytest.raises(helpers.client.QueryRuntimeException) as ei:
|
|
instance.query(
|
|
f"""
|
|
SELECT sum(a), sum(b), sum(c) FROM s3(
|
|
'http://{started_cluster.minio_host}:{started_cluster.minio_port}/{started_cluster.minio_bucket}/test_sts_smoke.csv',
|
|
'CSV', 'a Int64, b Int64, c Int64',
|
|
extra_credentials(role_arn = 'arn::role', role_session_name = 'mysession'))
|
|
SETTINGS s3_max_single_read_retries = 1, s3_retry_attempts = 1, s3_request_timeout_ms = 1000
|
|
"""
|
|
)
|
|
|
|
assert ei.value.returncode == 243
|
|
assert "HTTP response code: 403" in ei.value.stderr
|
|
|
|
assert "45\t450\t4500\n" == instance.query(
|
|
f"""
|
|
SELECT sum(a), sum(b), sum(c) FROM s3(
|
|
'http://{started_cluster.minio_host}:{started_cluster.minio_port}/{started_cluster.minio_bucket}/test_sts_smoke.csv',
|
|
'CSV', 'a Int64, b Int64, c Int64',
|
|
extra_credentials(role_arn = 'arn::role', role_session_name = 'miniorole'))
|
|
"""
|
|
)
|
|
|
|
|
|
def test_sts_external_id(started_cluster):
|
|
instance = started_cluster.instances["s3_with_environment_credentials"]
|
|
|
|
instance.query(
|
|
f"""
|
|
INSERT INTO FUNCTION s3('http://{started_cluster.minio_host}:{started_cluster.minio_port}/{started_cluster.minio_bucket}/test_sts_external_id.csv', 'minio', '{minio_secret_key}')
|
|
SELECT number, number * 10, number * 100 FROM numbers(10) SETTINGS s3_truncate_on_insert = 1"""
|
|
)
|
|
|
|
# Negative: the role session is accepted by the mock STS, but the supplied
|
|
# external id does not match, so AssumeRole returns credentials minio rejects.
|
|
# This only fails if `external_id` actually reaches the AssumeRole request.
|
|
with pytest.raises(helpers.client.QueryRuntimeException) as ei:
|
|
instance.query(
|
|
f"""
|
|
SELECT sum(a), sum(b), sum(c) FROM s3(
|
|
'http://{started_cluster.minio_host}:{started_cluster.minio_port}/{started_cluster.minio_bucket}/test_sts_external_id.csv',
|
|
'CSV', 'a Int64, b Int64, c Int64',
|
|
extra_credentials(role_arn = 'arn::role', role_session_name = 'miniorole', external_id = 'wrong_external_id'))
|
|
SETTINGS s3_max_single_read_retries = 1, s3_retry_attempts = 1, s3_request_timeout_ms = 1000
|
|
"""
|
|
)
|
|
|
|
assert ei.value.returncode == 243
|
|
assert "HTTP response code: 403" in ei.value.stderr
|
|
|
|
# Positive: matching role session name and external id yield working credentials.
|
|
assert "45\t450\t4500\n" == instance.query(
|
|
f"""
|
|
SELECT sum(a), sum(b), sum(c) FROM s3(
|
|
'http://{started_cluster.minio_host}:{started_cluster.minio_port}/{started_cluster.minio_bucket}/test_sts_external_id.csv',
|
|
'CSV', 'a Int64, b Int64, c Int64',
|
|
extra_credentials(role_arn = 'arn::role', role_session_name = 'miniorole', external_id = 'miniexternalid'))
|
|
"""
|
|
)
|
|
|
|
|
|
def test_sts_smoke_s3cluster(started_cluster):
|
|
instance = started_cluster.instances["s3_with_environment_credentials"]
|
|
|
|
instance.query(
|
|
f"""
|
|
INSERT INTO FUNCTION s3('http://{started_cluster.minio_host}:{started_cluster.minio_port}/{started_cluster.minio_bucket}/test_sts_smoke_s3cluster.csv', 'minio', '{minio_secret_key}')
|
|
SELECT number, number * 10, number * 100 FROM numbers(10) SETTINGS s3_truncate_on_insert = 1"""
|
|
)
|
|
|
|
with pytest.raises(helpers.client.QueryRuntimeException) as ei:
|
|
instance.query(
|
|
f"""
|
|
SELECT sum(a), sum(b), sum(c) FROM s3Cluster(
|
|
test_shard_localhost,
|
|
'http://{started_cluster.minio_host}:{started_cluster.minio_port}/{started_cluster.minio_bucket}/test_sts_smoke_s3cluster.csv',
|
|
'CSV', extra_credentials(role_arn = 'arn::role', role_session_name = 'mysession'))
|
|
SETTINGS s3_max_single_read_retries = 1, s3_retry_attempts = 1, s3_request_timeout_ms = 1000
|
|
"""
|
|
)
|
|
|
|
assert ei.value.returncode == 243
|
|
assert "DB::Exception: Failed to get object info" in ei.value.stderr
|
|
|
|
assert "45\t450\t4500\n" == instance.query(
|
|
f"""
|
|
SELECT sum(c1), sum(c2), sum(c3) FROM s3Cluster(
|
|
test_shard_localhost,
|
|
'http://{started_cluster.minio_host}:{started_cluster.minio_port}/{started_cluster.minio_bucket}/test_sts_smoke_s3cluster.csv',
|
|
'CSV', extra_credentials(role_arn = 'arn::role', role_session_name = 'miniorole'))
|
|
"""
|
|
)
|
|
|
|
|
|
def test_sts_credentials_cache(started_cluster):
|
|
instance = started_cluster.instances["s3_with_environment_credentials"]
|
|
|
|
instance.query(
|
|
f"""
|
|
INSERT INTO FUNCTION s3('http://{started_cluster.minio_host}:{started_cluster.minio_port}/{started_cluster.minio_bucket}/test_sts_smoke.csv', 'minio', '{minio_secret_key}')
|
|
SELECT number, number * 10, number * 100 FROM numbers(10) SETTINGS s3_truncate_on_insert = 1"""
|
|
)
|
|
|
|
for i in range(20):
|
|
assert "45\t450\t4500\n" == instance.query(
|
|
f"""
|
|
SELECT sum(a), sum(b), sum(c) FROM s3(
|
|
'http://{started_cluster.minio_host}:{started_cluster.minio_port}/{started_cluster.minio_bucket}/test_sts_smoke.csv',
|
|
'CSV', 'a Int64, b Int64, c Int64',
|
|
extra_credentials(role_arn = 'arn::role', role_session_name = 'miniorole'))
|
|
"""
|
|
)
|
|
|
|
added = int(
|
|
instance.query(
|
|
"SELECT value FROM system.events WHERE event = 'S3CachedCredentialsProvidersAdded'"
|
|
)
|
|
)
|
|
reused = int(
|
|
instance.query(
|
|
"SELECT value FROM system.events WHERE event = 'S3CachedCredentialsProvidersReused'"
|
|
)
|
|
)
|
|
|
|
assert added > 0 and reused > 0
|
|
assert reused > added
|
|
|
|
assert (
|
|
int(
|
|
instance.query(
|
|
"SELECT value FROM system.metrics WHERE name = 'S3CachedCredentialsProviders'"
|
|
)
|
|
)
|
|
> 0
|
|
)
|
|
|
|
for i in range(20):
|
|
with pytest.raises(helpers.client.QueryRuntimeException):
|
|
instance.query(
|
|
f"""
|
|
SELECT sum(a), sum(b), sum(c) FROM s3Cluster(
|
|
test_shard_localhost,
|
|
'http://{started_cluster.minio_host}:{started_cluster.minio_port}/{started_cluster.minio_bucket}/test_sts_smoke_s3cluster.csv',
|
|
'CSV', extra_credentials(role_arn = 'arn::role', role_session_name = 'mysession{i}'))
|
|
SETTINGS s3_max_single_read_retries = 1, s3_retry_attempts = 1, s3_request_timeout_ms = 1000
|
|
"""
|
|
)
|
|
|
|
assert (
|
|
int(
|
|
instance.query(
|
|
"SELECT value FROM system.metrics WHERE name = 'S3CachedCredentialsProviders'"
|
|
)
|
|
)
|
|
== 10
|
|
)
|