bool DaosZone::get_redirect_endpoint(std::string* endpoint) { return false; }
-bool DaosZone::has_zonegroup_api(const std::string& api) const { return false; }
-
const std::string& DaosZone::get_current_period_id() {
return current_period->get_id();
}
virtual const std::string& get_name() const override;
virtual bool is_writeable() override;
virtual bool get_redirect_endpoint(std::string* endpoint) override;
- virtual bool has_zonegroup_api(const std::string& api) const override;
virtual const std::string& get_current_period_id() override;
virtual const RGWAccessKey& get_system_key() {
return zone_params->system_key;
return false;
}
-bool MotrZone::has_zonegroup_api(const std::string& api) const
-{
- return (zonegroup.group.api_name == api);
-}
-
const std::string& MotrZone::get_current_period_id()
{
return current_period->get_id();
virtual const std::string& get_name() const override;
virtual bool is_writeable() override;
virtual bool get_redirect_endpoint(std::string* endpoint) override;
- virtual bool has_zonegroup_api(const std::string& api) const override;
virtual const std::string& get_current_period_id() override;
virtual const RGWAccessKey& get_system_key() { return zone_params->system_key; }
virtual const std::string& get_realm_name() { return realm->get_name(); }
return ret;
}
-int RGWPeriod::add_zonegroup(const DoutPrefixProvider *dpp, const RGWZoneGroup& zonegroup, optional_yield y)
-{
- if (zonegroup.realm_id != realm_id) {
- return 0;
- }
- int ret = period_map.update(zonegroup, cct);
- if (ret < 0) {
- ldpp_dout(dpp, 0) << "ERROR: updating period map: " << cpp_strerror(-ret) << dendl;
- return ret;
- }
-
- return store_info(dpp, false, y);
-}
-
int RGWPeriod::update(const DoutPrefixProvider *dpp, optional_yield y)
{
auto zone_svc = sysobj_svc->get_zone_svc();
return true;
}
-bool RadosZone::has_zonegroup_api(const std::string& api) const
-{
- return store->svc()->zone->has_zonegroup_api(api);
-}
-
const std::string& RadosZone::get_current_period_id()
{
return store->svc()->zone->get_current_period_id();
virtual const std::string& get_name() const override;
virtual bool is_writeable() override;
virtual bool get_redirect_endpoint(std::string* endpoint) override;
- virtual bool has_zonegroup_api(const std::string& api) const override;
virtual const std::string& get_current_period_id() override;
virtual const RGWAccessKey& get_system_key() override;
virtual const std::string& get_realm_name() override;
int create(const DoutPrefixProvider *dpp, optional_yield y, bool exclusive = true);
int delete_obj(const DoutPrefixProvider *dpp, optional_yield y);
int store_info(const DoutPrefixProvider *dpp, bool exclusive, optional_yield y);
- int add_zonegroup(const DoutPrefixProvider *dpp, const RGWZoneGroup& zonegroup, optional_yield y);
void fork();
int update(const DoutPrefixProvider *dpp, optional_yield y);
{ ERR_INVALID_DIGEST, {400, "InvalidDigest" }},
{ ERR_BAD_DIGEST, {400, "BadDigest" }},
{ ERR_INVALID_LOCATION_CONSTRAINT, {400, "InvalidLocationConstraint" }},
+ { ERR_ILLEGAL_LOCATION_CONSTRAINT_EXCEPTION, {400, "IllegalLocationConstraintException" }},
{ ERR_ZONEGROUP_DEFAULT_PLACEMENT_MISCONFIGURATION, {400, "ZonegroupDefaultPlacementMisconfiguration" }},
{ ERR_INVALID_BUCKET_NAME, {400, "InvalidBucketName" }},
{ ERR_INVALID_OBJECT_NAME, {400, "InvalidObjectName" }},
#define ERR_PRESIGNED_URL_EXPIRED 2223
#define ERR_PRESIGNED_URL_DISABLED 2224
#define ERR_AUTHORIZATION 2225 // SNS 403 AuthorizationError
+#define ERR_ILLEGAL_LOCATION_CONSTRAINT_EXCEPTION 2226
#define ERR_BUSY_RESHARDING 2300
#define ERR_NO_SUCH_ENTITY 2301
const rgw::SiteConfig& site = *s->penv.site;
const std::optional<RGWPeriod>& period = site.get_period();
const RGWZoneGroup& my_zonegroup = site.get_zonegroup();
-
- if (s->system_request) {
- // allow system requests to override the target zonegroup. for forwarded
- // requests, we'll create the bucket for the originating zonegroup
- createparams.zonegroup_id = s->info.args.get(RGW_SYS_PARAM_PREFIX "zonegroup");
- }
-
+ const std::string rgwx_zonegroup = s->info.args.get(RGW_SYS_PARAM_PREFIX "zonegroup");
const RGWZoneGroup* bucket_zonegroup = &my_zonegroup;
- if (createparams.zonegroup_id.empty()) {
- // default to the local zonegroup
- createparams.zonegroup_id = my_zonegroup.id;
- } else if (period) {
- auto z = period->period_map.zonegroups.find(createparams.zonegroup_id);
- if (z == period->period_map.zonegroups.end()) {
- ldpp_dout(this, 0) << "could not find zonegroup "
- << createparams.zonegroup_id << " in current period" << dendl;
- op_ret = -ENOENT;
- return;
- }
- bucket_zonegroup = &z->second;
- } else if (createparams.zonegroup_id != my_zonegroup.id) {
- ldpp_dout(this, 0) << "zonegroup does not match current zonegroup "
- << createparams.zonegroup_id << dendl;
- op_ret = -ENOENT;
- return;
- }
- // validate the LocationConstraint
+ // Validate LocationConstraint if it's provided and enforcement is strict
if (!location_constraint.empty() && !relaxed_region_enforcement) {
- // on the master zonegroup, allow any valid api_name. otherwise it has to
- // match the bucket's zonegroup
- if (period && my_zonegroup.is_master) {
- if (!period->period_map.zonegroups_by_api.count(location_constraint)) {
+ if (period) {
+ auto location_iter = period->period_map.zonegroups_by_api.find(location_constraint);
+ if (location_iter == period->period_map.zonegroups_by_api.end()) {
ldpp_dout(this, 0) << "location constraint (" << location_constraint
<< ") can't be found." << dendl;
op_ret = -ERR_INVALID_LOCATION_CONSTRAINT;
- s->err.message = "The specified location-constraint is not valid";
+ s->err.message = fmt::format("The {} location constraint is not valid.",
+ location_constraint);
return;
}
- } else if (bucket_zonegroup->api_name != location_constraint) {
+ bucket_zonegroup = &location_iter->second;
+ } else if (location_constraint != my_zonegroup.api_name) { // if we don't have a period, we can only use the current zonegroup - so check if the location matches by api name here
ldpp_dout(this, 0) << "location constraint (" << location_constraint
- << ") doesn't match zonegroup (" << bucket_zonegroup->api_name
- << ')' << dendl;
- op_ret = -ERR_INVALID_LOCATION_CONSTRAINT;
- s->err.message = "The specified location-constraint is not valid";
+ << ") doesn't match zonegroup (" << my_zonegroup.api_name << ")" << dendl;
+ op_ret = -ERR_ILLEGAL_LOCATION_CONSTRAINT_EXCEPTION;
+ s->err.message = fmt::format("The {} location constraint is incompatible "
+ "for the region specific endpoint this request was sent to.",
+ location_constraint);
return;
}
}
+ // If it's a system request, use the provided zonegroup if available
+ else if (s->system_request && !rgwx_zonegroup.empty()) {
+ if (period) {
+ auto zonegroup_iter = period->period_map.zonegroups.find(rgwx_zonegroup);
+ if (zonegroup_iter == period->period_map.zonegroups.end()) {
+ ldpp_dout(this, 0) << "could not find zonegroup " << rgwx_zonegroup
+ << " in current period" << dendl;
+ op_ret = -ENOENT;
+ return;
+ }
+ bucket_zonegroup = &zonegroup_iter->second;
+ }
+ }
+
+ const bool enforce_location_match =
+ !period || // No period: no multisite, so no need to enforce location match.
+ !s->system_request || // All user requests are enforced to match zonegroup's location.
+ !my_zonegroup.is_master; // but if it's a system request (forwarded) only allow remote creation on master zonegroup.
+ if (enforce_location_match && !my_zonegroup.equals(bucket_zonegroup->get_id())) {
+ ldpp_dout(this, 0) << "location constraint (" << bucket_zonegroup->api_name
+ << ") doesn't match zonegroup (" << my_zonegroup.api_name << ")" << dendl;
+ op_ret = -ERR_ILLEGAL_LOCATION_CONSTRAINT_EXCEPTION;
+ s->err.message = fmt::format("The {} location constraint is incompatible "
+ "for the region specific endpoint this request was sent to.",
+ bucket_zonegroup->api_name);
+ return;
+ }
+
+ // Set the final zonegroup ID
+ createparams.zonegroup_id = bucket_zonegroup->id;
// select and validate the placement target
op_ret = select_bucket_placement(this, *bucket_zonegroup, s->user->get_info(),
return;
}
- if (bucket_zonegroup == &my_zonegroup) {
+ if (my_zonegroup.equals(bucket_zonegroup->get_id())) {
// look up the zone placement pool
createparams.zone_placement = rgw::find_zone_placement(
this, site.get_zone_params(), createparams.placement_rule);
virtual bool is_writeable() = 0;
/** Get the URL for the endpoint for redirecting to this zone */
virtual bool get_redirect_endpoint(std::string* endpoint) = 0;
- /** Check to see if the given API is supported in this zone */
- virtual bool has_zonegroup_api(const std::string& api) const = 0;
/** Get the current period ID for this zone */
virtual const std::string& get_current_period_id() = 0;
/** Get thes system access key for this zone */
return false;
}
- bool DBZone::has_zonegroup_api(const std::string& api) const
- {
- if (api == "default")
- return true;
-
- return false;
- }
-
const std::string& DBZone::get_current_period_id()
{
return current_period->get_id();
virtual const std::string& get_name() const override;
virtual bool is_writeable() override;
virtual bool get_redirect_endpoint(std::string* endpoint) override;
- virtual bool has_zonegroup_api(const std::string& api) const override;
virtual const std::string& get_current_period_id() override;
virtual const RGWAccessKey& get_system_key() override;
virtual const std::string& get_realm_name() override;
virtual bool get_redirect_endpoint(std::string* endpoint) override {
return next->get_redirect_endpoint(endpoint);
}
- virtual bool has_zonegroup_api(const std::string& api) const override {
- return next->has_zonegroup_api(api);
- }
virtual const std::string& get_current_period_id() override {
return next->get_current_period_id();
}
return current_period->get_id();
}
-bool RGWSI_Zone::has_zonegroup_api(const std::string& api) const
-{
- if (!current_period->get_id().empty()) {
- const auto& zonegroups_by_api = current_period->get_map().zonegroups_by_api;
- if (zonegroups_by_api.find(api) != zonegroups_by_api.end())
- return true;
- } else if (zonegroup->api_name == api) {
- return true;
- }
- return false;
-}
-
bool RGWSI_Zone::zone_is_writeable()
{
return writeable_zone && !get_zone().is_read_only();
uint32_t get_zone_short_id() const;
const std::string& get_current_period_id() const;
- bool has_zonegroup_api(const std::string& api) const;
bool zone_is_writeable();
bool zone_syncs_from(const RGWZone& target_zone, const RGWZone& source_zone) const;
import boto.s3.connection
from boto.s3.website import WebsiteConfiguration
from boto.s3.cors import CORSConfiguration
+from botocore.exceptions import ClientError
from nose.tools import eq_ as eq
from nose.tools import assert_not_equal, assert_equal, assert_true, assert_false
CopySource = source_bucket.name + '/' + objname)
zonegroup_bucket_checkpoint(zonegroup_conns, dest_bucket.name)
-
+
+def test_bucket_create_location_constraint():
+ for zonegroup in realm.current_period.zonegroups:
+ zonegroup_conns = ZonegroupConns(zonegroup)
+ for zg in realm.current_period.zonegroups:
+ z = zonegroup_conns.rw_zones[0]
+ bucket_name = gen_bucket_name()
+ if zg.name == zonegroup.name:
+ # my zonegroup should pass
+ z.s3_client.create_bucket(Bucket=bucket_name, CreateBucketConfiguration={'LocationConstraint': zg.name})
+ # check bucket location
+ response = z.s3_client.get_bucket_location(Bucket=bucket_name)
+ assert_equal(response['LocationConstraint'], zg.name)
+ else:
+ # other zonegroup should fail with 400
+ e = assert_raises(ClientError,
+ z.s3_client.create_bucket,
+ Bucket=bucket_name,
+ CreateBucketConfiguration={'LocationConstraint': zg.name})
+ assert e.response['ResponseMetadata']['HTTPStatusCode'] == 400