Skip to content
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

Fix allowed_operations stability issue #4

Closed
wants to merge 8 commits into from
Closed
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Fixed
* Fixed `allowed_operations` stability issue

### Infrastructure
* Replace removed macOS 11 Big Sur in favour of macOS 12 Monterey in CI/CD

Expand Down
3 changes: 2 additions & 1 deletion b2/resource_b2_bucket.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,8 @@ func resourceB2BucketRead(ctx context.Context, d *schema.ResourceData, meta inte
const op = RESOURCE_READ

input := map[string]interface{}{
"bucket_id": d.Id(),
"bucket_id": d.Id(),
"cors_rules": d.Get("cors_rules"),
}

output, err := client.apply(name, op, input)
Expand Down
15 changes: 12 additions & 3 deletions b2/resource_b2_bucket_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,12 @@ func TestAccResourceB2Bucket_all(t *testing.T) {
resource.TestCheckResourceAttr(resourceName, "cors_rules.0.cors_rule_name", "downloadFromAnyOrigin"),
resource.TestCheckResourceAttr(resourceName, "cors_rules.0.allowed_origins.#", "1"),
resource.TestCheckResourceAttr(resourceName, "cors_rules.0.allowed_origins.0", "https"),
resource.TestCheckResourceAttr(resourceName, "cors_rules.0.allowed_operations.#", "2"),
resource.TestCheckResourceAttr(resourceName, "cors_rules.0.allowed_operations.#", "5"),
resource.TestCheckResourceAttr(resourceName, "cors_rules.0.allowed_operations.0", "b2_download_file_by_id"),
resource.TestCheckResourceAttr(resourceName, "cors_rules.0.allowed_operations.1", "b2_download_file_by_name"),
resource.TestCheckResourceAttr(resourceName, "cors_rules.0.allowed_operations.2", "s3_put"),
resource.TestCheckResourceAttr(resourceName, "cors_rules.0.allowed_operations.3", "s3_head"),
resource.TestCheckResourceAttr(resourceName, "cors_rules.0.allowed_operations.4", "s3_get"),
resource.TestCheckResourceAttr(resourceName, "cors_rules.0.expose_headers.#", "1"),
resource.TestCheckResourceAttr(resourceName, "cors_rules.0.expose_headers.0", "x-bz-content-sha1"),
resource.TestCheckResourceAttr(resourceName, "cors_rules.0.allowed_headers.#", "1"),
Expand Down Expand Up @@ -170,9 +173,12 @@ func TestAccResourceB2Bucket_update(t *testing.T) {
resource.TestCheckResourceAttr(resourceName, "cors_rules.0.cors_rule_name", "downloadFromAnyOrigin"),
resource.TestCheckResourceAttr(resourceName, "cors_rules.0.allowed_origins.#", "1"),
resource.TestCheckResourceAttr(resourceName, "cors_rules.0.allowed_origins.0", "https"),
resource.TestCheckResourceAttr(resourceName, "cors_rules.0.allowed_operations.#", "2"),
resource.TestCheckResourceAttr(resourceName, "cors_rules.0.allowed_operations.#", "5"),
resource.TestCheckResourceAttr(resourceName, "cors_rules.0.allowed_operations.0", "b2_download_file_by_id"),
resource.TestCheckResourceAttr(resourceName, "cors_rules.0.allowed_operations.1", "b2_download_file_by_name"),
resource.TestCheckResourceAttr(resourceName, "cors_rules.0.allowed_operations.2", "s3_put"),
resource.TestCheckResourceAttr(resourceName, "cors_rules.0.allowed_operations.3", "s3_head"),
resource.TestCheckResourceAttr(resourceName, "cors_rules.0.allowed_operations.4", "s3_get"),
resource.TestCheckResourceAttr(resourceName, "cors_rules.0.expose_headers.#", "1"),
resource.TestCheckResourceAttr(resourceName, "cors_rules.0.expose_headers.0", "x-bz-content-sha1"),
resource.TestCheckResourceAttr(resourceName, "cors_rules.0.allowed_headers.#", "1"),
Expand Down Expand Up @@ -304,7 +310,10 @@ resource "b2_bucket" "test" {
]
allowed_operations = [
"b2_download_file_by_id",
"b2_download_file_by_name"
"b2_download_file_by_name",
"s3_put",
"s3_head",
"s3_get",
]
expose_headers = ["x-bz-content-sha1"]
allowed_headers = ["range"]
Expand Down
2 changes: 1 addition & 1 deletion python-bindings/GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ format:

lint:
@black --check -Sl 100 ${DIR}
@flake8 --ignore=E501 ${DIR}
@flake8 --ignore=E501,W503 ${DIR}
@python ../scripts/check-headers.py '**/*.py'

testacc: build
Expand Down
33 changes: 28 additions & 5 deletions python-bindings/b2_terraform/provider_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,9 @@ class Bucket(Command):
tf_keys = BUCKET_KEYS

def data_source_read(self, *, bucket_name, **kwargs):
config_cors_rules = kwargs.get('cors_rules')
bucket = self.api.get_bucket_by_name(bucket_name)
return self._postprocess(bucket)
return self._postprocess(bucket, config_cors_rules=config_cors_rules)

def resource_create(
self,
Expand Down Expand Up @@ -244,14 +245,14 @@ def resource_create(
self.api.delete_bucket(bucket)
raise

return self._postprocess(bucket)
return self._postprocess(bucket, config_cors_rules=cors_rules)

def resource_read(self, *, bucket_id, **kwargs):
try:
bucket = self.api.get_bucket_by_id(bucket_id)
except BucketIdNotFound:
return None # no bucket has been found
return self._postprocess(bucket)
return self._postprocess(bucket, config_cors_rules=kwargs.get('cors_rules'))

def resource_update(
self,
Expand All @@ -278,7 +279,7 @@ def resource_update(
params.pop('is_file_lock_enabled', None) # this can only be set during bucket creation
self.api.session.update_bucket(**params)
bucket = self.api.get_bucket_by_id(bucket_id)
return self._postprocess(bucket)
return self._postprocess(bucket, config_cors_rules=cors_rules)

def resource_delete(self, *, bucket_id, **kwargs):
bucket = self.api.get_bucket_by_id(bucket_id)
Expand Down Expand Up @@ -352,7 +353,7 @@ def _preprocess(self, **kwargs):
}
return result

def _postprocess(self, obj, **kwargs):
def _postprocess(self, obj, config_cors_rules=None, **kwargs):
kwargs.update(obj.as_dict())
file_lock_configuration = kwargs['fileLockConfiguration'] = {}
for key in ('isFileLockEnabled', 'defaultRetention'):
Expand All @@ -361,8 +362,30 @@ def _postprocess(self, obj, **kwargs):
file_lock_configuration[key] = value

result = convert_json_to_go(kwargs, self.tf_keys)
self._order_allowed_operations(result.get('cors_rules', []), config_cors_rules or [])
return result

def _order_allowed_operations(self, cors_rules, config_cors_rules):
# B2 does not necessarily return allowed_operations in the same order as they were set.
# This can cause unnecessary diffs in the Terraform state.
# In order to avoid this, we sort the allowed_operations in the same order as they were set.
for cors_rules_item, config_cors_rules_item in zip(cors_rules, config_cors_rules):
allowed_operations = cors_rules_item.get('allowed_operations', [])
config_allowed_operations = (
config_cors_rules_item.get('allowedOperations')
or config_cors_rules_item.get('allowed_operations')
or []
)
if allowed_operations:

def sort_key(allowed_operation):
try:
return config_allowed_operations.index(allowed_operation)
except ValueError:
return -1

allowed_operations.sort(key=sort_key)


@B2Provider.register_subcommand
class BucketFileVersion(Command):
Expand Down
Loading