@@ -3695,6 +3695,84 @@ static int select_bucket_placement(const DoutPrefixProvider* dpp,
36953695 return 0 ;
36963696}
36973697
3698+ int put_swift_bucket_metadata (const DoutPrefixProvider* dpp,
3699+ req_state* s,
3700+ RGWAccessControlPolicy& policy,
3701+ bool const has_policy,
3702+ uint32_t policy_rw_mask,
3703+ const RGWCORSConfiguration& cors_config,
3704+ bool const has_cors,
3705+ std::optional<std::string> swift_ver_location,
3706+ const std::set<std::string>& rmattr_names,
3707+ optional_yield y) {
3708+ std::map<std::string, ceph::bufferlist> attrs;
3709+ int op_ret = rgw_get_request_metadata (dpp, s->cct , s->info , attrs, false );
3710+ if (op_ret < 0 ) {
3711+ return op_ret;
3712+ }
3713+
3714+ return retry_raced_bucket_write (
3715+ dpp, s->bucket .get (),
3716+ [s, has_policy, policy_rw_mask, &policy, cors_config, has_cors, &attrs,
3717+ dpp, rmattr_names, swift_ver_location] {
3718+ /* Encode special metadata first as we're using std::map::emplace under
3719+ * the hood. This method will add the new items only if the map doesn't
3720+ * contain such keys yet. */
3721+ if (has_policy) {
3722+ if (s->dialect .compare (" swift" ) == 0 ) {
3723+ rgw::swift::merge_policy (policy_rw_mask, s->bucket_acl , policy);
3724+ }
3725+ buffer::list bl;
3726+ policy.encode (bl);
3727+ attrs.emplace (RGW_ATTR_ACL, std::move (bl));
3728+ }
3729+
3730+ if (has_cors) {
3731+ buffer::list bl;
3732+ cors_config.encode (bl);
3733+ attrs.emplace (RGW_ATTR_CORS, std::move (bl));
3734+ }
3735+
3736+ /* It's supposed that following functions WILL NOT change any
3737+ * special attributes (like RGW_ATTR_ACL) if they are already
3738+ * present in attrs. */
3739+ prepare_add_del_attrs (s->bucket_attrs , rmattr_names, attrs);
3740+ populate_with_generic_attrs (s, attrs);
3741+
3742+ /* According to the Swift's behaviour and its container_quota
3743+ * WSGI middleware implementation: anyone with write permissions
3744+ * is able to set the bucket quota. This stays in contrast to
3745+ * account quotas that can be set only by clients holding
3746+ * reseller admin privileges. */
3747+ int ret = filter_out_quota_info (attrs, rmattr_names,
3748+ s->bucket ->get_info ().quota );
3749+ if (ret < 0 ) {
3750+ return ret;
3751+ }
3752+
3753+ if (swift_ver_location) {
3754+ s->bucket ->get_info ().swift_ver_location = *swift_ver_location;
3755+ s->bucket ->get_info ().swift_versioning =
3756+ (!swift_ver_location->empty ());
3757+ }
3758+
3759+ /* Web site of Swift API. */
3760+ filter_out_website (attrs, rmattr_names,
3761+ s->bucket ->get_info ().website_conf );
3762+ s->bucket ->get_info ().has_website =
3763+ !s->bucket ->get_info ().website_conf .is_empty ();
3764+
3765+ /* Setting attributes also stores the provided bucket info. Due
3766+ * to this fact, the new quota settings can be serialized with
3767+ * the same call. */
3768+ s->bucket ->set_attrs (attrs);
3769+ constexpr bool exclusive = false ; // overwrite
3770+ constexpr ceph::real_time no_set_mtime{};
3771+ return s->bucket ->put_info (dpp, exclusive, no_set_mtime, s->yield );
3772+ },
3773+ y);
3774+ }
3775+
36983776void RGWCreateBucket::execute (optional_yield y)
36993777{
37003778 op_ret = get_params (y);
@@ -3806,6 +3884,24 @@ void RGWCreateBucket::execute(optional_yield y)
38063884 return ;
38073885 }
38083886
3887+ // prevent re-creation with different index type or shard count
3888+ if ((createparams.index_type && *createparams.index_type !=
3889+ info.layout .current_index .layout .type ) ||
3890+ (createparams.index_shards && *createparams.index_shards !=
3891+ info.layout .current_index .layout .normal .num_shards )) {
3892+ s->err .message =
3893+ " Cannot modify existing bucket's index type or shard count" ;
3894+ op_ret = -EEXIST;
3895+ return ;
3896+ }
3897+
3898+ // don't allow changes to object lock
3899+ if (createparams.obj_lock_enabled != info.obj_lock_enabled ()) {
3900+ s->err .message = " Cannot modify existing bucket's object lock" ;
3901+ op_ret = -EEXIST;
3902+ return ;
3903+ }
3904+
38093905 // don't allow changes to the acl policy
38103906 RGWAccessControlPolicy old_policy;
38113907 int r = rgw_op_get_bucket_policy_from_attr (this , s->cct , driver, info.owner ,
@@ -3816,6 +3912,20 @@ void RGWCreateBucket::execute(optional_yield y)
38163912 op_ret = -EEXIST;
38173913 return ;
38183914 }
3915+
3916+ // For s3::CreateBucket just return back if bucket exists, as we do not allow
3917+ // any changes in bucket config param. need_metadata_upload() is always false
3918+ // for S3, so use the check to decide if its s3 request and not swift request.
3919+ if (!need_metadata_upload ()) {
3920+ op_ret = -ERR_BUCKET_EXISTS;
3921+ return ;
3922+ } else {
3923+ // For swift, update the bucket metadata and do not call createbucket.
3924+ op_ret = put_swift_bucket_metadata (
3925+ this , s, policy, has_policy, policy_rw_mask, cors_config, has_cors,
3926+ createparams.swift_ver_location , rmattr_names, y);
3927+ return ;
3928+ }
38193929 }
38203930
38213931 s->bucket_owner = policy.get_owner ();
@@ -3888,68 +3998,6 @@ void RGWCreateBucket::execute(optional_yield y)
38883998 /* continue if EEXIST and create_bucket will fail below. this way we can
38893999 * recover from a partial create by retrying it. */
38904000 ldpp_dout (this , 20 ) << " Bucket::create() returned ret=" << op_ret << " bucket=" << s->bucket << dendl;
3891-
3892- if (op_ret < 0 && op_ret != -EEXIST && op_ret != -ERR_BUCKET_EXISTS)
3893- return ;
3894-
3895- const bool existed = s->bucket_exists ;
3896- if (need_metadata_upload () && existed) {
3897- /* OK, it looks we lost race with another request. As it's required to
3898- * handle metadata fusion and upload, the whole operation becomes very
3899- * similar in nature to PutMetadataBucket. However, as the attrs may
3900- * changed in the meantime, we have to refresh. */
3901- short tries = 0 ;
3902- do {
3903- map<string, bufferlist> battrs;
3904-
3905- op_ret = s->bucket ->load_bucket (this , y);
3906- if (op_ret < 0 ) {
3907- return ;
3908- } else if (!s->auth .identity ->is_owner_of (s->bucket ->get_owner ())) {
3909- /* New bucket doesn't belong to the account we're operating on. */
3910- op_ret = -EEXIST;
3911- return ;
3912- } else {
3913- s->bucket_attrs = s->bucket ->get_attrs ();
3914- }
3915-
3916- createparams.attrs .clear ();
3917-
3918- op_ret = rgw_get_request_metadata (this , s->cct , s->info , createparams.attrs , false );
3919- if (op_ret < 0 ) {
3920- return ;
3921- }
3922- prepare_add_del_attrs (s->bucket_attrs , rmattr_names, createparams.attrs );
3923- populate_with_generic_attrs (s, createparams.attrs );
3924- op_ret = filter_out_quota_info (createparams.attrs , rmattr_names,
3925- s->bucket ->get_info ().quota );
3926- if (op_ret < 0 ) {
3927- return ;
3928- }
3929-
3930- /* Handle updates of the metadata for Swift's object versioning. */
3931- if (createparams.swift_ver_location ) {
3932- s->bucket ->get_info ().swift_ver_location = *createparams.swift_ver_location ;
3933- s->bucket ->get_info ().swift_versioning = !createparams.swift_ver_location ->empty ();
3934- }
3935-
3936- /* Web site of Swift API. */
3937- filter_out_website (createparams.attrs , rmattr_names,
3938- s->bucket ->get_info ().website_conf );
3939- s->bucket ->get_info ().has_website = !s->bucket ->get_info ().website_conf .is_empty ();
3940-
3941- /* This will also set the quota on the bucket. */
3942- s->bucket ->set_attrs (std::move (createparams.attrs ));
3943- constexpr bool exclusive = false ; // overwrite
3944- constexpr ceph::real_time no_set_mtime{};
3945- op_ret = s->bucket ->put_info (this , exclusive, no_set_mtime, y);
3946- } while (op_ret == -ECANCELED && tries++ < 20 );
3947-
3948- /* Restore the proper return code. */
3949- if (op_ret >= 0 ) {
3950- op_ret = -ERR_BUCKET_EXISTS;
3951- }
3952- } /* if (need_metadata_upload() && existed) */
39534001} /* RGWCreateBucket::execute() */
39544002
39554003int RGWDeleteBucket::verify_permission (optional_yield y)
@@ -5304,71 +5352,15 @@ void RGWPutMetadataBucket::execute(optional_yield y)
53045352 if (op_ret < 0 ) {
53055353 return ;
53065354 }
5307-
5308- op_ret = rgw_get_request_metadata (this , s->cct , s->info , attrs, false );
5309- if (op_ret < 0 ) {
5310- return ;
5311- }
5312-
53135355 if (!placement_rule.empty () &&
53145356 placement_rule != s->bucket ->get_placement_rule ()) {
53155357 op_ret = -EEXIST;
53165358 return ;
53175359 }
53185360
5319- op_ret = retry_raced_bucket_write (this , s->bucket .get (), [this ] {
5320- /* Encode special metadata first as we're using std::map::emplace under
5321- * the hood. This method will add the new items only if the map doesn't
5322- * contain such keys yet. */
5323- if (has_policy) {
5324- if (s->dialect .compare (" swift" ) == 0 ) {
5325- rgw::swift::merge_policy (policy_rw_mask, s->bucket_acl , policy);
5326- }
5327- buffer::list bl;
5328- policy.encode (bl);
5329- emplace_attr (RGW_ATTR_ACL, std::move (bl));
5330- }
5331-
5332- if (has_cors) {
5333- buffer::list bl;
5334- cors_config.encode (bl);
5335- emplace_attr (RGW_ATTR_CORS, std::move (bl));
5336- }
5337-
5338- /* It's supposed that following functions WILL NOT change any
5339- * special attributes (like RGW_ATTR_ACL) if they are already
5340- * present in attrs. */
5341- prepare_add_del_attrs (s->bucket_attrs , rmattr_names, attrs);
5342- populate_with_generic_attrs (s, attrs);
5343-
5344- /* According to the Swift's behaviour and its container_quota
5345- * WSGI middleware implementation: anyone with write permissions
5346- * is able to set the bucket quota. This stays in contrast to
5347- * account quotas that can be set only by clients holding
5348- * reseller admin privileges. */
5349- op_ret = filter_out_quota_info (attrs, rmattr_names, s->bucket ->get_info ().quota );
5350- if (op_ret < 0 ) {
5351- return op_ret;
5352- }
5353-
5354- if (swift_ver_location) {
5355- s->bucket ->get_info ().swift_ver_location = *swift_ver_location;
5356- s->bucket ->get_info ().swift_versioning = (!swift_ver_location->empty ());
5357- }
5358-
5359- /* Web site of Swift API. */
5360- filter_out_website (attrs, rmattr_names, s->bucket ->get_info ().website_conf );
5361- s->bucket ->get_info ().has_website = !s->bucket ->get_info ().website_conf .is_empty ();
5362-
5363- /* Setting attributes also stores the provided bucket info. Due
5364- * to this fact, the new quota settings can be serialized with
5365- * the same call. */
5366- s->bucket ->set_attrs (attrs);
5367- constexpr bool exclusive = false ; // overwrite
5368- constexpr ceph::real_time no_set_mtime{};
5369- op_ret = s->bucket ->put_info (this , exclusive, no_set_mtime, s->yield );
5370- return op_ret;
5371- }, y);
5361+ op_ret = put_swift_bucket_metadata (this , s, policy, has_policy,
5362+ policy_rw_mask, cors_config, has_cors,
5363+ swift_ver_location, rmattr_names, y);
53725364}
53735365
53745366int RGWPutMetadataObject::verify_permission (optional_yield y)
0 commit comments