Skip to content
Merged
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
2 changes: 2 additions & 0 deletions qa/tasks/rgw_multisite.py
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,8 @@ def create_zonegroup(cluster, gateways, period, config):
if endpoints:
# replace client names with their gateway endpoints
config['endpoints'] = extract_gateway_endpoints(gateways, endpoints)
if not config.get('api_name'): # otherwise it will be set to an empty string
config['api_name'] = config['name']
zonegroup = multisite.ZoneGroup(config['name'], period)
# `zonegroup set` needs --default on command line, and 'is_master' in json
args = is_default_arg(config)
Expand Down
2 changes: 0 additions & 2 deletions src/rgw/driver/daos/rgw_sal_daos.cc
Original file line number Diff line number Diff line change
Expand Up @@ -858,8 +858,6 @@ bool DaosZone::is_writeable() { return true; }

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();
}
Expand Down
1 change: 0 additions & 1 deletion src/rgw/driver/daos/rgw_sal_daos.h
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,6 @@ class DaosZone : public StoreZone {
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;
Expand Down
5 changes: 0 additions & 5 deletions src/rgw/driver/motr/rgw_sal_motr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1111,11 +1111,6 @@ bool MotrZone::get_redirect_endpoint(std::string* endpoint)
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();
Expand Down
1 change: 0 additions & 1 deletion src/rgw/driver/motr/rgw_sal_motr.h
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,6 @@ class MotrZone : public StoreZone {
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(); }
Expand Down
14 changes: 0 additions & 14 deletions src/rgw/driver/rados/rgw_period.cc
Original file line number Diff line number Diff line change
Expand Up @@ -68,20 +68,6 @@ int RGWPeriod::delete_obj(const DoutPrefixProvider *dpp, optional_yield y)
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();
Expand Down
5 changes: 0 additions & 5 deletions src/rgw/driver/rados/rgw_sal_rados.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4257,11 +4257,6 @@ bool RadosZone::get_redirect_endpoint(std::string* endpoint)
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();
Expand Down
1 change: 0 additions & 1 deletion src/rgw/driver/rados/rgw_sal_rados.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ class RadosZone : public StoreZone {
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;
Expand Down
1 change: 0 additions & 1 deletion src/rgw/driver/rados/rgw_zone.h
Original file line number Diff line number Diff line change
Expand Up @@ -769,7 +769,6 @@ class RGWPeriod
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);
Expand Down
1 change: 1 addition & 0 deletions src/rgw/rgw_common.cc
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ rgw_http_errors rgw_http_s3_errors({
{ 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" }},
Expand Down
1 change: 1 addition & 0 deletions src/rgw/rgw_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@ inline constexpr const char* RGW_REST_STS_XMLNS =
#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 // also in cls_rgw_types.h, don't change!
#define ERR_NO_SUCH_ENTITY 2301
Expand Down
82 changes: 45 additions & 37 deletions src/rgw/rgw_op.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3564,54 +3564,62 @@ void RGWCreateBucket::execute(optional_yield y)
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(),
Expand All @@ -3620,7 +3628,7 @@ void RGWCreateBucket::execute(optional_yield y)
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);
Expand Down
2 changes: 0 additions & 2 deletions src/rgw/rgw_sal.h
Original file line number Diff line number Diff line change
Expand Up @@ -1733,8 +1733,6 @@ class Zone {
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 */
Expand Down
8 changes: 0 additions & 8 deletions src/rgw/rgw_sal_dbstore.cc
Original file line number Diff line number Diff line change
Expand Up @@ -458,14 +458,6 @@ namespace rgw::sal {
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();
Expand Down
1 change: 0 additions & 1 deletion src/rgw/rgw_sal_dbstore.h
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,6 @@ class DBNotification : public StoreNotification {
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;
Expand Down
3 changes: 0 additions & 3 deletions src/rgw/rgw_sal_filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,6 @@ class FilterZone : public Zone {
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();
}
Expand Down
12 changes: 0 additions & 12 deletions src/rgw/services/svc_zone.cc
Original file line number Diff line number Diff line change
Expand Up @@ -657,18 +657,6 @@ const string& RGWSI_Zone::get_current_period_id() const
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();
Expand Down
1 change: 0 additions & 1 deletion src/rgw/services/svc_zone.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ class RGWSI_Zone : public RGWServiceInstance
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;
Expand Down
22 changes: 21 additions & 1 deletion src/test/rgw/rgw_multi/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
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
Expand Down Expand Up @@ -3634,4 +3635,23 @@ def test_copy_object_different_bucket():
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