return store->meta_mgr->put_entry(bucket_meta_handler, bucket_name, bl, exclusive, objv_tracker, mtime, pattrs);
}
-
+#warning removed RGWBucket::create_bucket(), clean this up when ready
+#if 0
int RGWBucket::create_bucket(string bucket_str, string& user_id, string& region_name, string& display_name)
{
RGWAccessControlPolicy policy, old_policy;
rgw_bucket& bucket = bucket_info.bucket;
RGWBucketInfo new_info;
+ string placement_rule;
- ret = store->create_bucket(user_id, bucket, region_name, attrs, objv_tracker,
+ ret = store->create_bucket(user_info, bucket, region_name, placement_rule, attrs, objv_tracker,
NULL, bucket_info.creation_time, NULL, &new_info);
if (ret && ret != -EEXIST)
goto done;
done:
return ret;
}
+#endif
int rgw_bucket_set_attrs(RGWRados *store, rgw_obj& obj,
map<string, bufferlist>& attrs,
store = storage;
- RGWUserInfo info;
RGWBucketInfo bucket_info;
- user_id = op_state.get_user_id();
+ string user_id = op_state.get_user_id();
bucket_name = op_state.get_bucket_name();
RGWUserBuckets user_buckets;
}
if (!user_id.empty()) {
- int r = rgw_get_user_info_by_uid(store, user_id, info);
+ int r = rgw_get_user_info_by_uid(store, user_id, user_info);
if (r < 0)
return r;
- op_state.display_name = info.display_name;
+ op_state.display_name = user_info.display_name;
}
clear_failure();
std::string display_name = op_state.get_user_display_name();
rgw_bucket bucket = op_state.get_bucket();
- string uid_str(user_id);
+ string uid_str(user_info.user_id);
bufferlist aclbl;
rgw_obj obj(bucket, no_oid);
RGWObjVersionTracker objv_tracker;
// now update the user for the bucket...
if (display_name.empty()) {
- ldout(store->ctx(), 0) << "WARNING: user " << user_id << " has no display name set" << dendl;
+ ldout(store->ctx(), 0) << "WARNING: user " << user_info.user_id << " has no display name set" << dendl;
}
- policy.create_default(user_id, display_name);
+ policy.create_default(user_info.user_id, display_name);
owner = policy.get_owner();
r = store->set_bucket_owner(bucket, owner);
if (r < 0)
return r;
- r = rgw_add_bucket(store, user_id, bucket, 0);
+ r = rgw_add_bucket(store, user_info.user_id, bucket, 0);
if (r < 0)
return r;
- } else {
+ }
+#warning not creating bucket on bucket link, clean this up later
+#if 0
+ else {
// the bucket seems not to exist, so we should probably create it...
r = create_bucket(bucket_name.c_str(), uid_str, store->region.name, display_name);
if (r < 0) {
return r;
}
+#endif
return 0;
}
return -EINVAL;
}
- int r = rgw_remove_user_bucket_info(store, user_id, bucket);
+ int r = rgw_remove_user_bucket_info(store, user_info.user_id, bucket);
if (r < 0) {
set_err_msg(err_msg, "error unlinking bucket" + cpp_strerror(-r));
}
if (ret == -ENOENT || old_bci.info.bucket.bucket_id != bci.info.bucket.bucket_id) {
/* a new bucket, we need to select a new bucket placement for it */
rgw_bucket bucket;
- ret = store->select_bucket_placement(entry, bucket);
+ ret = store->set_bucket_location_by_rule(bci.info.placement_rule, entry, bucket);
if (ret < 0) {
ldout(store->ctx(), 0) << "ERROR: select_bucket_placement() returned " << ret << dendl;
return ret;
RGWRados *store;
RGWAccessHandle handle;
- std::string user_id;
+ RGWUserInfo user_info;
std::string bucket_name;
bool failure;
RGWBucket() : store(NULL), failure(false) {}
int init(RGWRados *storage, RGWBucketAdminOpState& op_state);
- int create_bucket(string bucket_str, string& user_id, string& region_name, string& display_name);
-
int check_bad_index_multipart(RGWBucketAdminOpState& op_state,
list<std::string>& objs_to_unlink, std::string *err_msg = NULL);
uint32_t flags;
string region;
time_t creation_time;
+ string placement_rule;
void encode(bufferlist& bl) const {
- ENCODE_START(6, 4, bl);
+ ENCODE_START(7, 4, bl);
::encode(bucket, bl);
::encode(owner, bl);
::encode(flags, bl);
::encode(region, bl);
::encode(creation_time, bl);
+ ::encode(placement_rule, bl);
ENCODE_FINISH(bl);
}
void decode(bufferlist::iterator& bl) {
::decode(region, bl);
if (struct_v >= 6)
::decode(creation_time, bl);
+ if (struct_v >= 7)
+ ::decode(placement_rule, bl);
DECODE_FINISH(bl);
}
void dump(Formatter *f) const;
encode_json("owner", owner, f);
encode_json("flags", flags, f);
encode_json("region", region, f);
+ encode_json("placement_rule", region, f);
}
void RGWBucketInfo::decode_json(JSONObj *obj) {
JSONDecoder::decode_json("owner", owner, obj);
JSONDecoder::decode_json("flags", flags, obj);
JSONDecoder::decode_json("region", region, obj);
+ JSONDecoder::decode_json("placement_rule", region, obj);
}
void RGWObjEnt::dump(Formatter *f) const
encode_json("user_keys_pool", user_keys_pool.data_pool, f);
encode_json("user_email_pool", user_email_pool.data_pool, f);
encode_json("user_swift_pool", user_swift_pool.data_pool, f);
- encode_json("user_uid_pool ", user_uid_pool.data_pool, f);
+ encode_json("user_uid_pool", user_uid_pool.data_pool, f);
encode_json_plain("system_key", system_key, f);
- encode_json("placement_pools ", placement_pools, f);
+ encode_json("placement_pools", placement_pools, f);
}
static void decode_json(const char *field, rgw_bucket& bucket, JSONObj *obj)
encode_json("master_zone", master_zone, f);
encode_json_map("zones", zones, f); /* more friendly representation */
encode_json_map("placement_targets", placement_targets, f); /* more friendly representation */
+ encode_json("default_placement", default_placement, f);
}
static void decode_zones(map<string, RGWZone>& zones, JSONObj *o)
JSONDecoder::decode_json("master_zone", master_zone, obj);
JSONDecoder::decode_json("zones", zones, decode_zones, obj);
JSONDecoder::decode_json("placement_targets", placement_targets, decode_placement_targets, obj);
+ JSONDecoder::decode_json("default_placement", default_placement, obj);
}
attrs[RGW_ATTR_ACL] = aclbl;
s->bucket.name = s->bucket_name_str;
- ret = store->create_bucket(s->user.user_id, s->bucket, region_name, attrs, objv_tracker, pobjv,
+ ret = store->create_bucket(s->user, s->bucket, region_name, placement_rule, attrs, objv_tracker, pobjv,
creation_time, pmaster_bucket, &info, true);
/* continue if EEXIST and create_bucket will fail below. this way we can recover
* from a partial create by retrying it. */
int ret;
RGWAccessControlPolicy policy;
string location_constraint;
+ string placement_rule;
RGWObjVersionTracker objv_tracker;
RGWBucketInfo info;
is_master = true;
+ RGWRegionPlacementTarget placement_target;
+ placement_target.name = "default-placement";
+ placement_targets[placement_target.name] = placement_target;
+ default_placement = "default-placement";
+
RGWZone& default_zone = zones[zone_name];
default_zone.name = zone_name;
user_email_pool = ".users.email";
user_swift_pool = ".users.swift";
user_uid_pool = ".users.uid";
+
+ RGWZonePlacementInfo default_placement;
+ default_placement.index_pool = ".rgw.buckets";
+ default_placement.data_pool = ".rgw.buckets";
+ placement_pools["default-placement"] = default_placement;
+
+ RGWZonePlacementInfo test_placement;
+ test_placement.index_pool = ".rgw.test.index";
+ test_placement.data_pool = ".rgw.test.data";
+ placement_pools["test"] = test_placement;
}
string RGWZoneParams::get_pool_name(CephContext *cct)
* create a bucket with name bucket and the given list of attrs
* returns 0 on success, -ERR# otherwise.
*/
-int RGWRados::create_bucket(string& owner, rgw_bucket& bucket,
+int RGWRados::create_bucket(RGWUserInfo& owner, rgw_bucket& bucket,
const string& region_name,
+ const string& placement_rule,
map<std::string, bufferlist>& attrs,
RGWObjVersionTracker& objv_tracker,
obj_version *pobjv,
bool exclusive)
{
#define MAX_CREATE_RETRIES 20 /* need to bound retries */
+ string selected_placement_rule;
for (int i = 0; i < MAX_CREATE_RETRIES; i++) {
int ret = 0;
- ret = select_bucket_placement(bucket.name, bucket);
+ ret = select_bucket_placement(owner, region_name, placement_rule, bucket.name, bucket, &selected_placement_rule);
if (ret < 0)
return ret;
bufferlist bl;
RGWBucketInfo info;
info.bucket = bucket;
- info.owner = owner;
+ info.owner = owner.user_id;
info.region = region_name;
+ info.placement_rule = selected_placement_rule;
if (!creation_time)
time(&info.creation_time);
else
return -ENOENT;
}
-int RGWRados::select_bucket_placement(string& bucket_name, rgw_bucket& bucket)
+int RGWRados::select_new_bucket_location(RGWUserInfo& user_info, const string& region_name, const string& request_rule,
+ const string& bucket_name, rgw_bucket& bucket, string *pselected_rule)
+{
+ /* first check that rule exists within the specific region */
+ map<string, RGWRegion>::iterator riter = region_map.regions.find(region_name);
+ if (riter == region_map.regions.end()) {
+ ldout(cct, 0) << "could not find region " << region_name << " in region map" << dendl;
+ return -EINVAL;
+ }
+ /* now check that tag exists within region */
+ RGWRegion& region = riter->second;
+
+ /* find placement rule. Hierarchy: request rule > user default rule > region default rule */
+ string rule = request_rule;
+ if (rule.empty()) {
+ rule = user_info.default_placement;
+ if (rule.empty())
+ rule = region.default_placement;
+ }
+
+ if (rule.empty()) {
+ ldout(cct, 0) << "misconfiguration, should not have an empty placement rule name" << dendl;
+ return -EIO;
+ }
+
+ if (!rule.empty()) {
+ map<string, RGWRegionPlacementTarget>::iterator titer = region.placement_targets.find(rule);
+ if (titer == region.placement_targets.end()) {
+ ldout(cct, 0) << "could not find placement rule " << rule << " within region " << dendl;
+ return -EINVAL;
+ }
+
+ /* now check tag for the rule, whether user is permitted to use rule */
+ RGWRegionPlacementTarget& target_rule = titer->second;
+ if (!target_rule.user_permitted(user_info.placement_tags)) {
+ ldout(cct, 0) << "user not permitted to use placement rule" << dendl;
+ return -EPERM;
+ }
+ }
+
+ /* yay, user is permitted, now just make sure that zone has this rule configured. We're
+ * checking it for the local zone, because that's where this bucket object is going to
+ * reside.
+ */
+ map<string, RGWZonePlacementInfo>::iterator piter = zone.placement_pools.find(rule);
+ if (piter == zone.placement_pools.end()) {
+ /* couldn't find, means we cannot really place data for this bucket in this zone */
+ if ((region_name.empty() && region.is_master) ||
+ region_name == region.name) {
+ /* that's a configuration error, zone should have that rule, as we're within the requested
+ * region */
+ return -EINVAL;
+ } else {
+ /* oh, well, data is not going to be placed here, bucket object is just a placeholder */
+ return 0;
+ }
+ }
+
+ if (pselected_rule)
+ *pselected_rule = rule;
+
+ return set_bucket_location_by_rule(rule, bucket_name, bucket);
+}
+
+int RGWRados::set_bucket_location_by_rule(const string& location_rule, const std::string& bucket_name, rgw_bucket& bucket)
+{
+ bucket.name = bucket_name;
+
+ map<string, RGWZonePlacementInfo>::iterator piter = zone.placement_pools.find(location_rule);
+ if (piter == zone.placement_pools.end()) {
+ /* silently ignore, bucket will not reside in this zone */
+ return 0;
+ }
+
+ RGWZonePlacementInfo& placement_info = piter->second;
+
+ bucket.data_pool = placement_info.data_pool;
+ bucket.index_pool = placement_info.index_pool;
+
+ return 0;
+
+}
+
+int RGWRados::select_bucket_placement(RGWUserInfo& user_info, const string& region_name, const string& placement_rule,
+ const string& bucket_name, rgw_bucket& bucket, string *pselected_rule)
{
bufferlist map_bl;
map<string, bufferlist> m;
string pool_name;
bool write_map = false;
+ if (!zone.placement_pools.empty()) {
+ return select_new_bucket_location(user_info, region_name, placement_rule, bucket_name, bucket, pselected_rule);
+ }
+
rgw_obj obj(zone.domain_root, avail_pools);
int ret = rgw_get_system_obj(this, NULL, zone.domain_root, avail_pools, map_bl, NULL, NULL);
pool_name = miter->first;
}
bucket.data_pool = pool_name;
-#warning FIXME
bucket.index_pool = pool_name;
bucket.name = bucket_name;
string name;
list<string> tags;
- bool tag_exists(const string& tag) {
- for (list<string>::iterator iter = tags.begin(); iter != tags.end(); ++iter) {
- if (tag == *iter) {
- return true;
+ bool user_permitted(list<string>& user_tags) {
+ if (tags.empty()) {
+ return true;
+ }
+ for (list<string>::iterator uiter = user_tags.begin(); uiter != user_tags.end(); ++uiter) { /* we don't expect many of either, so we can handle this kind of lookup */
+ string& rule = *uiter;
+ for (list<string>::iterator iter = tags.begin(); iter != tags.end(); ++iter) {
+ if (rule == *iter) {
+ return true;
+ }
}
}
return false;
map<string, RGWZone> zones;
map<string, RGWRegionPlacementTarget> placement_targets;
+ string default_placement;
CephContext *cct;
RGWRados *store;
::encode(endpoints, bl);
::encode(master_zone, bl);
::encode(zones, bl);
+ ::encode(placement_targets, bl);
+ ::encode(default_placement, bl);
ENCODE_FINISH(bl);
}
::decode(endpoints, bl);
::decode(master_zone, bl);
::decode(zones, bl);
+ ::decode(placement_targets, bl);
+ ::decode(default_placement, bl);
DECODE_FINISH(bl);
}
* returns 0 on success, -ERR# otherwise.
*/
virtual int init_bucket_index(rgw_bucket& bucket);
- int select_bucket_placement(std::string& bucket_name, rgw_bucket& bucket);
- virtual int create_bucket(string& owner, rgw_bucket& bucket,
+ int select_bucket_placement(RGWUserInfo& user_info, const string& region_name, const std::string& rule,
+ const std::string& bucket_name, rgw_bucket& bucket, string *pselected_rule);
+ int select_new_bucket_location(RGWUserInfo& user_info, const string& region_name, const string& rule,
+ const std::string& bucket_name, rgw_bucket& bucket, string *pselected_rule);
+ int set_bucket_location_by_rule(const string& location_rule, const std::string& bucket_name, rgw_bucket& bucket);
+ virtual int create_bucket(RGWUserInfo& owner, rgw_bucket& bucket,
const string& region_name,
+ const string& placement_rule,
map<std::string,bufferlist>& attrs,
RGWObjVersionTracker& objv_tracker,
obj_version *pobjv,
ldout(s->cct, 10) << "create bucket location constraint: " << location_constraint << dendl;
}
+ int pos = location_constraint.find(':');
+ if (pos >= 0) {
+ placement_rule = location_constraint.substr(pos + 1);
+ location_constraint = location_constraint.substr(0, pos);
+ }
+
return 0;
}