Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 4.3k
ARROW-15906: [C++][Python][R] By default, don't create or delete S3 buckets#13206
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
94e61661e65e1d300c9159a8486ccd979a13e319e20a65bb8c52568f25adf4ab961c26b1bb3bc749300b31abe7c02a1db076addc5367efd34164e11deb99f3File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -99,6 +99,12 @@ cdef class S3FileSystem(FileSystem): | ||
| Note: S3 buckets are special and the operations available on them may be | ||
| limited or more expensive than desired. | ||
| When S3FileSystem creates new buckets (assuming allow_bucket_creation is | ||
| True), it does not pass any non-default settings. In AWS S3, the bucket and | ||
| all objects will be not publicly visible, and will have no bucket policies | ||
| and no resource tags. To have more control over how buckets are created, | ||
| use a different API to create them. | ||
| Parameters | ||
| ---------- | ||
| access_key : str, default None | ||
| @@ -150,6 +156,12 @@ cdef class S3FileSystem(FileSystem): | ||
| S3FileSystem(proxy_options={'scheme': 'http', 'host': 'localhost', | ||
| 'port': 8020, 'username': 'username', | ||
| 'password': 'password'}) | ||
| allow_bucket_creation : bool, default False | ||
| Whether to allow CreateDir at the bucket-level. This option may also be | ||
| passed in a URI query parameter. | ||
| allow_bucket_deletion : bool, default False | ||
| Whether to allow DeleteDir at the bucket-level. This option may also be | ||
| passed in a URI query parameter. | ||
| """ | ||
| cdef: | ||
| @@ -159,7 +171,8 @@ cdef class S3FileSystem(FileSystem): | ||
| bint anonymous=False, region=None, scheme=None, | ||
| endpoint_override=None, bint background_writes=True, | ||
| default_metadata=None, role_arn=None, session_name=None, | ||
| external_id=None, load_frequency=900, proxy_options=None): | ||
| external_id=None, load_frequency=900, proxy_options=None, | ||
| allow_bucket_creation=False, allow_bucket_deletion=False): | ||
| cdef: | ||
| CS3Options options | ||
| shared_ptr[CS3FileSystem] wrapped | ||
| @@ -253,6 +266,9 @@ cdef class S3FileSystem(FileSystem): | ||
| "'proxy_options': expected 'dict' or 'str', " | ||
| f"got {type(proxy_options)} instead.") | ||
| options.allow_bucket_creation = allow_bucket_creation | ||
| options.allow_bucket_deletion = allow_bucket_deletion | ||
wjones127 marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| with nogil: | ||
| wrapped = GetResultValue(CS3FileSystem.Make(options)) | ||
| @@ -295,14 +311,16 @@ cdef class S3FileSystem(FileSystem): | ||
| external_id=frombytes(opts.external_id), | ||
| load_frequency=opts.load_frequency, | ||
| background_writes=opts.background_writes, | ||
| allow_bucket_creation=opts.allow_bucket_creation, | ||
| allow_bucket_deletion=opts.allow_bucket_deletion, | ||
| default_metadata=pyarrow_wrap_metadata(opts.default_metadata), | ||
| proxy_options={'scheme': frombytes(opts.proxy_options.scheme), | ||
| 'host': frombytes(opts.proxy_options.host), | ||
| 'port': opts.proxy_options.port, | ||
| 'username': frombytes( | ||
| opts.proxy_options.username), | ||
| 'password': frombytes( | ||
| opts.proxy_options.password)} | ||
| opts.proxy_options.password)}, | ||
| ),) | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -2495,6 +2495,7 @@ def s3_example_simple(s3_server): | ||
| host, port, access_key, secret_key = s3_server['connection'] | ||
| uri = ( | ||
| "s3://{}:{}@mybucket/data.parquet?scheme=http&endpoint_override={}:{}" | ||
| "&allow_bucket_creation=True" | ||
| .format(access_key, secret_key, host, port) | ||
| ) | ||
| @@ -2557,9 +2558,10 @@ def test_open_dataset_from_s3_with_filesystem_uri(s3_server): | ||
| host, port, access_key, secret_key = s3_server['connection'] | ||
| bucket = 'theirbucket' | ||
| path = 'nested/folder/data.parquet' | ||
| uri = "s3://{}:{}@{}/{}?scheme=http&endpoint_override={}:{}".format( | ||
| access_key, secret_key, bucket, path, host, port | ||
| ) | ||
| uri = "s3://{}:{}@{}/{}?scheme=http&endpoint_override={}:{}"\ | ||
| "&allow_bucket_creation=true".format( | ||
| access_key, secret_key, bucket, path, host, port | ||
| ) | ||
| fs, path = FileSystem.from_uri(uri) | ||
| assert path == 'theirbucket/nested/folder/data.parquet' | ||
| @@ -4529,9 +4531,38 @@ def test_write_dataset_s3_put_only(s3_server): | ||
| ).to_table() | ||
| assert result.equals(table) | ||
| # Passing create_dir is fine if the bucket already exists | ||
| ds.write_dataset( | ||
| table, "existing-bucket", filesystem=fs, | ||
| format="feather", create_dir=True, partitioning=part, | ||
| existing_data_behavior='overwrite_or_ignore' | ||
| ) | ||
| # check roundtrip | ||
| result = ds.dataset( | ||
| "existing-bucket", filesystem=fs, format="ipc", partitioning="hive" | ||
| ).to_table() | ||
| assert result.equals(table) | ||
| # Error enforced by filesystem | ||
| with pytest.raises(OSError, | ||
| match="Bucket 'non-existing-bucket' not found"): | ||
| ds.write_dataset( | ||
| table, "non-existing-bucket", filesystem=fs, | ||
wjones127 marked this conversation as resolved.
Outdated
Uh oh!There was an error while loading. Please reload this page. | ||
| format="feather", create_dir=True, | ||
| existing_data_behavior='overwrite_or_ignore' | ||
| ) | ||
| # Error enforced by minio / S3 service | ||
| fs = S3FileSystem( | ||
| access_key='limited', | ||
| secret_key='limited123', | ||
| endpoint_override='{}:{}'.format(host, port), | ||
| scheme='http', | ||
| allow_bucket_creation=True, | ||
| ) | ||
| with pytest.raises(OSError, match="Access Denied"): | ||
| ds.write_dataset( | ||
| table, "existing-bucket", filesystem=fs, | ||
| table, "non-existing-bucket", filesystem=fs, | ||
| format="feather", create_dir=True, | ||
| existing_data_behavior='overwrite_or_ignore' | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -212,7 +212,9 @@ def s3fs(request, s3_server): | ||
| access_key=access_key, | ||
| secret_key=secret_key, | ||
| endpoint_override='{}:{}'.format(host, port), | ||
| scheme='http' | ||
| scheme='http', | ||
| allow_bucket_creation=True, | ||
| allow_bucket_deletion=True | ||
| ) | ||
| fs.create_dir(bucket) | ||
Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you also add tests in | ||
| @@ -443,6 +445,12 @@ def test_s3fs_limited_permissions_create_bucket(s3_server): | ||
| ) | ||
| fs.create_dir('existing-bucket/test') | ||
| with pytest.raises(pa.ArrowIOError, match="Bucket 'new-bucket' not found"): | ||
| fs.create_dir('new-bucket') | ||
| with pytest.raises(pa.ArrowIOError, match="Would delete bucket"): | ||
| fs.delete_dir('existing-bucket') | ||
| def test_file_info_constructor(): | ||
| dt = datetime.fromtimestamp(1568799826, timezone.utc) | ||
| @@ -1036,6 +1044,10 @@ def test_s3_options(): | ||
| assert isinstance(fs, S3FileSystem) | ||
| assert pickle.loads(pickle.dumps(fs)) == fs | ||
| fs = S3FileSystem(allow_bucket_creation=True, allow_bucket_deletion=True) | ||
| assert isinstance(fs, S3FileSystem) | ||
| assert pickle.loads(pickle.dumps(fs)) == fs | ||
| with pytest.raises(ValueError): | ||
| S3FileSystem(access_key='access') | ||
| with pytest.raises(ValueError): | ||
| @@ -1308,8 +1320,9 @@ def test_filesystem_from_uri_s3(s3_server): | ||
| host, port, access_key, secret_key = s3_server['connection'] | ||
| uri = "s3://{}:{}@mybucket/foo/bar?scheme=http&endpoint_override={}:{}" \ | ||
| .format(access_key, secret_key, host, port) | ||
| uri = "s3://{}:{}@mybucket/foo/bar?scheme=http&endpoint_override={}:{}"\ | ||
| "&allow_bucket_creation=True" \ | ||
| .format(access_key, secret_key, host, port) | ||
| fs, path = FileSystem.from_uri(uri) | ||
| assert isinstance(fs, S3FileSystem) | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.