$ radosgw-admin metadata get bucket:<bucket>
$ radosgw-admin metadata get bucket.instance:<bucket>:<bucket_id>
-$ radosgw-admin metadata get user:<user> # or set
+$ radosgw-admin metadata get user:<user> # get or set
user: Holds user information
bucket: Holds a mapping between bucket name and bucket instance id
.rgw
<bucket>
- .bucket.meta.<bucket>:<marker>
+ .bucket.meta.<bucket>:<marker> # see put_bucket_instance_info()
+
+ The tenant is used to disambiguate buckets, but not bucket instances.
+ Example:
+
+ .bucket.meta.prodtx:test%25star:default.84099.6
+ .bucket.meta.testcont:default.4126.1
+ .bucket.meta.prodtx:testcont:default.84099.4
+ prodtx/testcont
+ prodtx/test%25star
+ testcont
.rgw.gc
gc.<N>
.users.uid
Contains _both_ per-user information (RGWUserInfo) in "<user>" objects
- and per-user bucket lists in omaps of "<user>.buckets" objects.
+ and per-user lists of buckets in omaps of "<user>.buckets" objects.
+ The "<user>" may contain the tenant if non-empty, for example:
+
+ prodtx$prodt
+ test2.buckets
+ prodtx$prodt.buckets
+ test2
.users.email
Unimportant
.rgw.buckets.index
Objects are named ".dir.<marker>", each contains a bucket index.
+ If the index is sharded, each shard appends the shard index after
+ the marker.
.rgw.buckets
default.7593.4__shadow_.488urDFerTYXavx4yAd-Op8mxehnvTI_1
<marker>_<key>
An example of a marker would be "default.16004.1" or "default.7593.4".
+The current format is "<zone>.<instance_id>.<bucket_id>". But once
+generated, a marker is not parsed again, so its format may change
+freely in the future.
bool get_id(rgw_user& _id) {
switch(type.get_type()) {
case ACL_TYPE_EMAIL_USER:
- _id = email;
+ _id = email; // implies from_str() that parses the 't:u' syntax
return true;
case ACL_TYPE_GROUP:
return false;
ACLGroupTypeEnum get_group() { return group; }
void encode(bufferlist& bl) const {
- ENCODE_START(3, 3, bl);
+ ENCODE_START(4, 3, bl);
::encode(type, bl);
- ::encode(id, bl);
+ string s;
+ id.to_str(s);
+ ::encode(s, bl);
string uri;
::encode(uri, bl);
::encode(email, bl);
ENCODE_FINISH(bl);
}
void decode(bufferlist::iterator& bl) {
- DECODE_START_LEGACY_COMPAT_LEN(3, 3, 3, bl);
+ DECODE_START_LEGACY_COMPAT_LEN(4, 3, 3, bl);
::decode(type, bl);
- ::decode(id, bl);
+ string s;
+ ::decode(s, bl);
+ id.from_str(s);
string uri;
::decode(uri, bl);
::decode(email, bl);
ACLGroupTypeEnum uri_to_group(string& uri);
- void set_canon(rgw_user& _id, string& _name, int perm) {
+ void set_canon(const rgw_user& _id, string& _name, int perm) {
type.set(ACL_TYPE_CANON_USER);
id = _id;
name = _name;
multimap<string, ACLGrant>& get_grant_map() { return grant_map; }
- void create_default(rgw_user& id, string name) {
+ void create_default(const rgw_user& id, string name) {
acl_user_map.clear();
acl_group_map.clear();
}
void dump(Formatter *f) const;
static void generate_test_instances(list<ACLOwner*>& o);
- void set_id(rgw_user& _id) { id = _id; }
+ void set_id(const rgw_user& _id) { id = _id; }
void set_name(string& name) { display_name = name; }
rgw_user& get_id() { return id; }
return owner;
}
- void create_default(rgw_user& id, string& name) {
+ void create_default(const rgw_user& id, string& name) {
acl.create_default(id, name);
owner.set_id(id);
owner.set_name(name);
ldout(cct, 0) << "ERROR: src_grant.get_id() failed" << dendl;
return -EINVAL;
}
- email = u.id;
+ email = u.id; // XXX none of that .to_str() stuff here, but why?
ldout(cct, 10) << "grant user email=" << email << dendl;
if (rgw_get_user_info_by_email(store, email, grant_user) < 0) {
ldout(cct, 10) << "grant user email not found or other error" << dendl;
#ifndef CEPH_RGW_ACL_SWIFT_H
#define CEPH_RGW_ACL_SWIFT_H
+#include <list>
#include <map>
#include <string>
-#include <iostream>
-#include <list>
#include <include/types.h>
#include "rgw_acl.h"
}
};
-static int init_bucket(const string& tenant, const string& bucket_name, const string& bucket_id,
+static int init_bucket(const string& tenant_name, const string& bucket_name, const string& bucket_id,
RGWBucketInfo& bucket_info, rgw_bucket& bucket)
{
if (!bucket_name.empty()) {
RGWObjectCtx obj_ctx(store);
int r;
if (bucket_id.empty()) {
- r = store->get_bucket_info(obj_ctx, tenant, bucket_name, bucket_info, NULL);
+ r = store->get_bucket_info(obj_ctx, tenant_name, bucket_name, bucket_info, NULL);
} else {
string bucket_instance_id = bucket_name + ":" + bucket_id;
r = store->get_bucket_instance_info(obj_ctx, bucket_instance_id, bucket_info, NULL, NULL);
}
}
-int set_bucket_quota(RGWRados *store, int opt_cmd, string& bucket_name, int64_t max_size, int64_t max_objects,
+int set_bucket_quota(RGWRados *store, int opt_cmd,
+ const string& tenant_name, const string& bucket_name,
+ int64_t max_size, int64_t max_objects,
bool have_max_size, bool have_max_objects)
{
RGWBucketInfo bucket_info;
map<string, bufferlist> attrs;
RGWObjectCtx obj_ctx(store);
- int r = store->get_bucket_info(obj_ctx, bucket_name, bucket_info, NULL, &attrs);
+ int r = store->get_bucket_info(obj_ctx, tenant_name, bucket_name, bucket_info, NULL, &attrs);
if (r < 0) {
cerr << "could not get bucket info for bucket=" << bucket_name << ": " << cpp_strerror(-r) << std::endl;
return -r;
return 0;
}
-int do_check_object_locator(const string& bucket_name, bool fix, bool remove_bad, Formatter *f)
+int do_check_object_locator(const string& tenant_name, const string& bucket_name,
+ bool fix, bool remove_bad, Formatter *f)
{
if (remove_bad && !fix) {
cerr << "ERROR: can't have remove_bad specified without fix" << std::endl;
f->open_object_section("bucket");
f->dump_string("bucket", bucket_name);
- int ret = init_bucket(bucket_name, bucket_id, bucket_info, bucket);
+ int ret = init_bucket(tenant_name, bucket_name, bucket_id, bucket_info, bucket);
if (ret < 0) {
cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
return ret;
return 0;
}
-
int main(int argc, char **argv)
{
vector<const char*> args;
usage();
return 0;
} else if (ceph_argparse_witharg(args, i, &val, "-i", "--uid", (char*)NULL)) {
- string s = val;
- if (!tenant.empty()) {
- s = tenant + ":" + val;
- }
- user_id.from_str(s);
- tenant = user_id.tenant;
+ user_id.from_str(val);
} else if (ceph_argparse_witharg(args, i, &val, "--tenant", (char*)NULL)) {
tenant = val;
} else if (ceph_argparse_witharg(args, i, &val, "--access-key", (char*)NULL)) {
++i;
}
}
+ if (tenant.empty()) {
+ tenant = user_id.tenant;
+ } else {
+ if (user_id.empty()) {
+ cerr << "ERROR: --tennant is set, but there's no user ID" << std::endl;
+ return EINVAL;
+ }
+ user_id.tenant = tenant;
+ }
if (args.empty()) {
return usage();
/* populate bucket operation */
bucket_op.set_bucket_name(bucket_name);
- bucket_op.set_tenant(tenant);
bucket_op.set_object(object);
bucket_op.set_check_objects(check_objects);
bucket_op.set_delete_children(delete_child_objects);
RGWBucketAdminOp::info(store, bucket_op, f);
} else {
RGWBucketInfo bucket_info;
- int ret = init_bucket(bucket_name, bucket_id, bucket_info, bucket);
+ int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
if (ret < 0) {
cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
return -ret;
return EINVAL;
}
RGWBucketInfo bucket_info;
- int ret = init_bucket(bucket_name, tenant, bucket_id, bucket_info, bucket);
+ int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
if (ret < 0) {
cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
return -ret;
if (opt_cmd == OPT_BI_GET) {
RGWBucketInfo bucket_info;
- int ret = init_bucket(bucket_name, bucket_id, bucket_info, bucket);
+ int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
if (ret < 0) {
cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
return -ret;
if (opt_cmd == OPT_BI_PUT) {
RGWBucketInfo bucket_info;
- int ret = init_bucket(bucket_name, bucket_id, bucket_info, bucket);
+ int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
if (ret < 0) {
cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
return -ret;
if (opt_cmd == OPT_BI_LIST) {
RGWBucketInfo bucket_info;
- int ret = init_bucket(bucket_name, bucket_id, bucket_info, bucket);
+ int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
if (ret < 0) {
cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
return -ret;
cerr << "ERROR: need to specify bucket name" << std::endl;
return EINVAL;
}
- do_check_object_locator(bucket_name, fix, remove_bad, formatter);
+ do_check_object_locator(tenant, bucket_name, fix, remove_bad, formatter);
} else {
RGWBucketAdminOp::check_index(store, bucket_op, f);
}
if (opt_cmd == OPT_USER_STATS) {
if (sync_stats) {
if (!bucket_name.empty()) {
- int ret = rgw_bucket_sync_user_stats(store, bucket_name);
+ int ret = rgw_bucket_sync_user_stats(store, tenant, bucket_name);
if (ret < 0) {
cerr << "ERROR: could not sync bucket stats: " << cpp_strerror(-ret) << std::endl;
return -ret;
cerr << "ERROR: invalid quota scope specification." << std::endl;
return EINVAL;
}
- set_bucket_quota(store, opt_cmd, bucket_name, max_size, max_objects, have_max_size, have_max_objects);
+ set_bucket_quota(store, opt_cmd, tenant, bucket_name,
+ max_size, max_objects, have_max_size, have_max_objects);
} else if (!user_id.empty()) {
if (quota_scope == "bucket") {
set_user_bucket_quota(opt_cmd, user, user_op, max_size, max_objects, have_max_size, have_max_objects);
void to_str(std::string& str) const {
if (!tenant.empty()) {
- str = tenant + ':' + id;
+ str = tenant + '$' + id;
} else {
str = id;
}
}
void from_str(const std::string& str) {
- ssize_t pos = str.find(':');
+ ssize_t pos = str.find('$');
if (pos >= 0) {
tenant = str.substr(0, pos);
id = str.substr(pos + 1);
buckets_obj_id += RGW_BUCKETS_OBJ_SUFFIX;
}
+/*
+ * Note that this is not a reversal of parse_bucket(). That one deals
+ * with the syntax we need in metadata and such. This one deals with
+ * the representation in RADOS pools. We chose '/' because it's not
+ * acceptable in bucket names and thus qualified buckets cannot conflict
+ * with the legacy or S3 buckets.
+ */
+void rgw_make_bucket_entry_name(const string& tenant_name, const string& bucket_name, string& bucket_entry) {
+ if (tenant_name.empty()) {
+ bucket_entry = bucket_name;
+ } else {
+ bucket_entry = tenant_name + "/" + bucket_name;
+ }
+}
+
+/*
+ * Tenants are separated from buckets in URLs by a colon in S3.
+ * This function is not to be used on Swift URLs, not even for COPY arguments.
+ */
+void rgw_parse_url_bucket(const string &bucket,
+ string &tenant_name, string &bucket_name) {
+ int pos = bucket.find(':');
+ tenant_name = bucket.substr(0, pos);
+ bucket_name = bucket.substr(pos + 1);
+}
+
/**
* Get all the buckets owned by a user and fill up an RGWUserBuckets with them.
* Returns: 0 on success, -ERR# on failure.
return store->cls_user_sync_bucket_stats(obj, bucket);
}
-int rgw_bucket_sync_user_stats(RGWRados *store, const string& bucket_name)
+int rgw_bucket_sync_user_stats(RGWRados *store, const string& tenant_name, const string& bucket_name)
{
RGWBucketInfo bucket_info;
RGWObjectCtx obj_ctx(store);
- int ret = store->get_bucket_info(obj_ctx, bucket_name, bucket_info, NULL);
+ int ret = store->get_bucket_info(obj_ctx, tenant_name, bucket_name, bucket_info, NULL);
if (ret < 0) {
ldout(store->ctx(), 0) << "ERROR: could not fetch bucket info: ret=" << ret << dendl;
return ret;
int rgw_link_bucket(RGWRados *store, const rgw_user& user_id, rgw_bucket& bucket, time_t creation_time, bool update_entrypoint)
{
int ret;
+ // XXX Actually, should we use user_id.tenant when creating bucket?
+ string& tenant_name = bucket.tenant;
string& bucket_name = bucket.name;
cls_user_bucket_entry new_bucket;
RGWObjectCtx obj_ctx(store);
if (update_entrypoint) {
- ret = store->get_bucket_entrypoint_info(obj_ctx, bucket_name, ep, &ot, NULL, &attrs);
+ ret = store->get_bucket_entrypoint_info(obj_ctx, tenant_name, bucket_name, ep, &ot, NULL, &attrs);
if (ret < 0 && ret != -ENOENT) {
ldout(store->ctx(), 0) << "ERROR: store->get_bucket_entrypoint_info() returned " << ret << dendl;
} else if (ret >= 0 && ep.linked && ep.owner != user_id) {
ep.linked = true;
ep.owner = user_id;
- ret = store->put_bucket_entrypoint_info(bucket_name, ep, false, ot, 0, &attrs);
+ ret = store->put_bucket_entrypoint_info(tenant_name, bucket_name, ep, false, ot, 0, &attrs);
if (ret < 0)
goto done_err;
return 0;
done_err:
- int r = rgw_unlink_bucket(store, user_id, bucket.name);
+ int r = rgw_unlink_bucket(store, user_id, bucket.tenant, bucket.name);
if (r < 0) {
ldout(store->ctx(), 0) << "ERROR: failed unlinking bucket on error cleanup: " << cpp_strerror(-r) << dendl;
}
return ret;
}
-int rgw_unlink_bucket(RGWRados *store, const rgw_user& user_id, const string& bucket_name, bool update_entrypoint)
+int rgw_unlink_bucket(RGWRados *store, const rgw_user& user_id, const string& tenant_name, const string& bucket_name, bool update_entrypoint)
{
int ret;
RGWObjVersionTracker ot;
map<string, bufferlist> attrs;
RGWObjectCtx obj_ctx(store);
- ret = store->get_bucket_entrypoint_info(obj_ctx, user_id.tenant, bucket_name, ep, &ot, NULL, &attrs);
+ ret = store->get_bucket_entrypoint_info(obj_ctx, tenant_name, bucket_name, ep, &ot, NULL, &attrs);
if (ret == -ENOENT)
return 0;
if (ret < 0)
}
ep.linked = false;
- ret = store->put_bucket_entrypoint_info(bucket_name, ep, false, ot, 0, &attrs);
+ ret = store->put_bucket_entrypoint_info(tenant_name, bucket_name, ep, false, ot, 0, &attrs);
if (ret < 0)
return ret;
if (!bucket_info.has_instance_obj) {
/* an old bucket object, need to convert it */
RGWObjectCtx obj_ctx(store);
- int ret = store->convert_old_bucket_info(obj_ctx, bucket.name);
+ int ret = store->convert_old_bucket_info(obj_ctx, bucket.tenant, bucket.name);
if (ret < 0) {
ldout(store->ctx(), 0) << "ERROR: failed converting old bucket info: " << ret << dendl;
return ret;
obj.bucket = bucket;
- ret = store->get_bucket_info(obj_ctx, bucket.name, info, NULL);
+ ret = store->get_bucket_info(obj_ctx, bucket.tenant, bucket.name, info, NULL);
if (ret < 0)
return ret;
return ret;
}
- ret = rgw_unlink_bucket(store, info.owner, bucket.name);
+ ret = rgw_unlink_bucket(store, info.owner, bucket.tenant, bucket.name);
if (ret < 0) {
lderr(store->ctx()) << "ERROR: unable to remove user bucket information" << dendl;
}
return ret;
}
-int rgw_bucket_delete_bucket_obj(RGWRados *store, string& bucket_name, RGWObjVersionTracker& objv_tracker)
+int rgw_bucket_delete_bucket_obj(RGWRados *store,
+ const string& tenant_name,
+ const string& bucket_name,
+ RGWObjVersionTracker& objv_tracker)
{
- return store->meta_mgr->remove_entry(bucket_meta_handler, bucket_name, &objv_tracker);
+ string key;
+
+ rgw_make_bucket_entry_name(tenant_name, bucket_name, key);
+ return store->meta_mgr->remove_entry(bucket_meta_handler, key, &objv_tracker);
}
static void set_err_msg(std::string *sink, std::string msg)
store = storage;
rgw_user user_id = op_state.get_user_id();
+ tenant = user_id.tenant;
bucket_name = op_state.get_bucket_name();
- tenant = op_state.get_tenant();
RGWUserBuckets user_buckets;
RGWObjectCtx obj_ctx(store);
return -EIO;
}
- r = rgw_unlink_bucket(store, owner.get_id(), bucket.name);
+ r = rgw_unlink_bucket(store, owner.get_id(), bucket.tenant, bucket.name);
if (r < 0) {
set_err_msg(err_msg, "could not unlink policy from user " + owner.get_id().to_str());
return r;
return -EINVAL;
}
- int r = rgw_unlink_bucket(store, user_info.user_id, bucket.name);
+ int r = rgw_unlink_bucket(store, user_info.user_id, bucket.tenant, bucket.name);
if (r < 0) {
set_err_msg(err_msg, "error unlinking bucket" + cpp_strerror(-r));
}
RGWBucketInfo bucket_info;
map<string, bufferlist> attrs;
- int ret = store->get_bucket_info(obj_ctx, bucket.name, bucket_info, NULL, &attrs);
+ int ret = store->get_bucket_info(obj_ctx, bucket.tenant, bucket.name, bucket_info, NULL, &attrs);
if (ret < 0) {
return ret;
}
int RGWBucketAdminOp::get_policy(RGWRados *store, RGWBucketAdminOpState& op_state,
ostream& os)
{
- RGWBucket bucket;
+ RGWBucket bucket;
int ret = bucket.init(store, op_state);
if (ret < 0)
return bucket.remove_object(op_state);
}
-static int bucket_stats(RGWRados *store, std::string& tenant, std::string& bucket_name, Formatter *formatter)
+static int bucket_stats(RGWRados *store, const std::string& tenant_name, std::string& bucket_name, Formatter *formatter)
{
RGWBucketInfo bucket_info;
rgw_bucket bucket;
time_t mtime;
RGWObjectCtx obj_ctx(store);
- int r = store->get_bucket_info(obj_ctx, tenant, bucket_name, bucket_info, &mtime);
+ int r = store->get_bucket_info(obj_ctx, tenant_name, bucket_name, bucket_info, &mtime);
if (r < 0)
return r;
size_t max_entries = cct->_conf->rgw_list_buckets_max_chunk;
bool show_stats = op_state.will_fetch_stats();
- string tenant = op_state.get_tenant();
+ rgw_user user_id = op_state.get_user_id();
if (op_state.is_user_op()) {
formatter->open_array_section("buckets");
bool done;
do {
- ret = rgw_read_user_buckets(store, op_state.get_user_id(), buckets, marker, max_entries, false);
+ ret = rgw_read_user_buckets(store, user_id, buckets, marker, max_entries, false);
if (ret < 0)
return ret;
for (iter = m.begin(); iter != m.end(); ++iter) {
std::string obj_name = iter->first;
if (show_stats)
- bucket_stats(store, tenant, obj_name, formatter);
+ bucket_stats(store, user_id.tenant, obj_name, formatter);
else
formatter->dump_string("bucket", obj_name);
formatter->close_section();
} else if (!bucket_name.empty()) {
- bucket_stats(store, tenant, bucket_name, formatter);
+ bucket_stats(store, user_id.tenant, bucket_name, formatter);
} else {
RGWAccessHandle handle;
while (store->list_buckets_next(obj, &handle) >= 0) {
formatter->dump_string("bucket", obj.key.name);
if (show_stats)
- bucket_stats(store, tenant, obj.key.name, formatter);
+ bucket_stats(store, user_id.tenant, obj.key.name, formatter);
}
}
map<string, bufferlist> attrs;
RGWObjectCtx obj_ctx(store);
- int ret = store->get_bucket_entrypoint_info(obj_ctx, entry, be, &ot, &mtime, &attrs);
+ string tenant_name, bucket_name;
+ parse_bucket(entry, tenant_name, bucket_name);
+ int ret = store->get_bucket_entrypoint_info(obj_ctx, tenant_name, bucket_name, be, &ot, &mtime, &attrs);
if (ret < 0)
return ret;
RGWObjVersionTracker old_ot;
RGWObjectCtx obj_ctx(store);
- int ret = store->get_bucket_entrypoint_info(obj_ctx, entry, old_be, &old_ot, &orig_mtime, &attrs);
+ string tenant_name, bucket_name;
+ parse_bucket(entry, tenant_name, bucket_name);
+ int ret = store->get_bucket_entrypoint_info(obj_ctx, tenant_name, bucket_name, old_be, &old_ot, &orig_mtime, &attrs);
if (ret < 0 && ret != -ENOENT)
return ret;
objv_tracker.read_version = old_ot.read_version; /* maintain the obj version we just read */
- ret = store->put_bucket_entrypoint_info(entry, be, false, objv_tracker, mtime, &attrs);
+ ret = store->put_bucket_entrypoint_info(tenant_name, bucket_name, be, false, objv_tracker, mtime, &attrs);
if (ret < 0)
return ret;
if (be.linked) {
ret = rgw_link_bucket(store, be.owner, be.bucket, be.creation_time, false);
} else {
- ret = rgw_unlink_bucket(store, be.owner, be.bucket.name, false);
+ ret = rgw_unlink_bucket(store, be.owner, be.bucket.tenant, be.bucket.name, false);
}
return ret;
RGWBucketEntryPoint be;
RGWObjectCtx obj_ctx(store);
- int ret = store->get_bucket_entrypoint_info(obj_ctx, entry, be, &objv_tracker, NULL, NULL);
+ string tenant_name, bucket_name;
+ parse_bucket(entry, tenant_name, bucket_name);
+ int ret = store->get_bucket_entrypoint_info(obj_ctx, tenant_name, bucket_name, be, &objv_tracker, NULL, NULL);
if (ret < 0)
return ret;
* it immediately and don't want to invalidate our cached objv_version or the bucket obj removal
* will incorrectly fail.
*/
- ret = rgw_unlink_bucket(store, be.owner, entry, false);
+ ret = rgw_unlink_bucket(store, be.owner, tenant_name, bucket_name, false);
if (ret < 0) {
lderr(store->ctx()) << "could not unlink bucket=" << entry << " owner=" << be.owner << dendl;
}
- ret = rgw_bucket_delete_bucket_obj(store, entry, objv_tracker);
+ ret = rgw_bucket_delete_bucket_obj(store, tenant_name, bucket_name, objv_tracker);
if (ret < 0) {
lderr(store->ctx()) << "could not delete bucket=" << entry << dendl;
}
return 0;
}
- int put(RGWRados *store, string& oid, RGWObjVersionTracker& objv_tracker,
+ int put(RGWRados *store, string& entry, RGWObjVersionTracker& objv_tracker,
time_t mtime, JSONObj *obj, sync_type_t sync_type) {
RGWBucketCompleteInfo bci, old_bci;
decode_json_obj(bci, obj);
time_t orig_mtime;
RGWObjectCtx obj_ctx(store);
- int ret = store->get_bucket_instance_info(obj_ctx, oid, old_bci.info, &orig_mtime, &old_bci.attrs);
+ int ret = store->get_bucket_instance_info(obj_ctx, entry, old_bci.info,
+ &orig_mtime, &old_bci.attrs);
bool exists = (ret != -ENOENT);
if (ret < 0 && exists)
return ret;
-
if (!exists || old_bci.info.bucket.bucket_id != bci.info.bucket.bucket_id) {
/* a new bucket, we need to select a new bucket placement for it */
+ // XXX not sure if this is correct -- stolen from Radoslaw; what about get()?
+ string tenant_name;
+ string bucket_name;
+ parse_bucket(entry, tenant_name, bucket_name);
+
rgw_bucket bucket;
- ret = store->set_bucket_location_by_rule(bci.info.placement_rule, oid, bucket);
+ ret = store->set_bucket_location_by_rule(bci.info.placement_rule,
+ tenant_name, bucket_name, bucket);
if (ret < 0) {
ldout(store->ctx(), 0) << "ERROR: select_bucket_placement() returned " << ret << dendl;
return ret;
extern int rgw_bucket_instance_remove_entry(RGWRados *store, string& entry, RGWObjVersionTracker *objv_tracker);
-extern int rgw_bucket_delete_bucket_obj(RGWRados *store, string& bucket_name, RGWObjVersionTracker& objv_tracker);
+extern int rgw_bucket_delete_bucket_obj(RGWRados *store,
+ const string& tenant_name,
+ const string& bucket_name,
+ RGWObjVersionTracker& objv_tracker);
extern int rgw_bucket_sync_user_stats(RGWRados *store, const rgw_user& user_id, rgw_bucket& bucket);
-extern int rgw_bucket_sync_user_stats(RGWRados *store, const string& bucket_name);
+extern int rgw_bucket_sync_user_stats(RGWRados *store, const string& tenant_name, const string& bucket_name);
+
+extern void rgw_make_bucket_entry_name(const string& tenant_name,
+ const string& bucket_name,
+ string& bucket_entry);
+extern void rgw_parse_url_bucket(const string &bucket,
+ string &tenant_name, string &bucket_name);
/**
* Store a list of the user's buckets, with associated functinos.
uint64_t default_amount = 1000);
extern int rgw_link_bucket(RGWRados *store, const rgw_user& user_id, rgw_bucket& bucket, time_t creation_time, bool update_entrypoint = true);
-extern int rgw_unlink_bucket(RGWRados *store, const rgw_user& user_id, const string& bucket_name, bool update_entrypoint = true);
+extern int rgw_unlink_bucket(RGWRados *store, const rgw_user& user_id,
+ const string& tenant_name, const string& bucket_name, bool update_entrypoint = true);
extern int rgw_remove_object(RGWRados *store, RGWBucketInfo& bucket_info, rgw_bucket& bucket, rgw_obj_key& key);
extern int rgw_remove_bucket(RGWRados *store, rgw_bucket& bucket, bool delete_children);
struct RGWBucketAdminOpState {
rgw_user uid;
- std::string tenant;
std::string display_name;
std::string bucket_name;
std::string bucket_id;
void set_user_id(rgw_user& user_id) {
if (!user_id.empty())
uid = user_id;
- tenant = uid.tenant;
- }
- void set_tenant(string& t) {
- tenant = t;
}
void set_bucket_name(std::string& bucket_str) {
bucket_name = bucket_str;
std::string& get_user_display_name() { return display_name; }
std::string& get_bucket_name() { return bucket_name; }
std::string& get_object_name() { return object_name; }
- std::string& get_tenant() { return tenant; };
rgw_bucket& get_bucket() { return bucket; }
void set_bucket(rgw_bucket& _bucket) {
bucket_exists = false;
has_bad_meta = false;
length = NULL;
- copy_source = NULL;
http_auth = NULL;
local_source = false;
#include "include/types.h"
#include "include/utime.h"
#include "rgw_acl.h"
+#include "rgw_basic_types.h"
#include "rgw_cors.h"
#include "rgw_quota.h"
#include "rgw_string.h"
#include "cls/user/cls_user_types.h"
#include "cls/rgw/cls_rgw_types.h"
#include "include/rados/librados.hpp"
-#include "rgw_basic_types.h"
using namespace std;
::encode(bucket_quota, bl);
::encode(temp_url_keys, bl);
::encode(user_quota, bl);
- ::encode(user_id, bl);
+ ::encode(user_id.tenant, bl);
ENCODE_FINISH(bl);
}
void decode(bufferlist::iterator& bl) {
}
::decode(display_name, bl);
::decode(user_email, bl);
+ /* We populate swift_keys map later nowadays, but we have to decode. */
string swift_name;
string swift_key;
if (struct_v >= 3) ::decode(swift_name, bl);
if (struct_v >= 4) ::decode(swift_key, bl);
- if (struct_v < 13) {
- user_id.tenant.clear();
- }
if (struct_v >= 5)
::decode(user_id.id, bl);
else
::decode(user_quota, bl);
}
if (struct_v >= 17) {
- ::decode(user_id, bl);
+ ::decode(user_id.tenant, bl);
+ } else {
+ user_id.tenant.clear();
}
DECODE_FINISH(bl);
}
data_pool = index_pool = n;
marker = "";
}
- rgw_bucket(const char *n, const char *dp, const char *ip, const char *m, const char *id, const char *h) :
- name(n), data_pool(dp), index_pool(ip), marker(m), bucket_id(id) {}
+ rgw_bucket(const char *t, const char *n, const char *dp, const char *ip, const char *m, const char *id, const char *h) :
+ tenant(t), name(n), data_pool(dp), index_pool(ip), marker(m), bucket_id(id) {}
void convert(cls_user_bucket *b) {
b->name = name;
b->bucket_id = bucket_id;
}
- rgw_bucket(const char *t, const char *n, const char *p, const char *m, const char *id) :
- tenant(t), name(n), pool(p), marker(m), bucket_id(id) {}
void encode(bufferlist& bl) const {
ENCODE_START(8, 3, bl);
::encode(name, bl);
::encode(num_shards, bl);
::encode(bucket_index_shard_hash_type, bl);
::encode(requester_pays, bl);
- ::encode(owner, bl);
+ ::encode(owner.tenant, bl);
ENCODE_FINISH(bl);
}
void decode(bufferlist::iterator& bl) {
if (struct_v >= 12)
::decode(requester_pays, bl);
if (struct_v >= 13)
- ::decode(owner, bl);
+ ::decode(owner.tenant, bl);
DECODE_FINISH(bl);
}
void dump(Formatter *f) const;
uint32_t perm_mask;
utime_t header_time;
+ /* Set once when req_state is initialized and not violated thereafter */
+ string bucket_tenant;
+ string bucket_name;
+
rgw_bucket bucket;
- string bucket_name_str;
rgw_obj_key object;
+ string src_tenant_name;
string src_bucket_name;
rgw_obj_key src_object;
ACLOwner bucket_owner;
bool has_bad_meta;
RGWUserInfo user;
- string tenant;
RGWAccessControlPolicy *bucket_acl;
RGWAccessControlPolicy *object_acl;
string canned_acl;
bool has_acl_header;
- const char *copy_source;
const char *http_auth;
bool local_source; /* source is local */
#include "common/OutputDataSocket.h"
#include "common/Formatter.h"
+#include "rgw_bucket.h"
#include "rgw_log.h"
#include "rgw_acl.h"
#include "rgw_rados.h"
rgw_user user;
- if (!s->bucket_name_str.empty())
+ if (!s->bucket_name.empty())
user = s->bucket_owner.get_id();
else
user = s->user.user_id;
if (!s->enable_ops_log)
return 0;
- if (s->bucket_name_str.empty()) {
+ if (s->bucket_name.empty()) {
ldout(s->cct, 5) << "nothing to log for operation" << dendl;
return -EINVAL;
}
} else {
bucket_id = s->bucket.bucket_id;
}
- entry.bucket = s->bucket_name_str;
+ string bucket_log;
+ rgw_make_bucket_entry_name(s->bucket_tenant, s->bucket_name, bucket_log);
+ entry.bucket = bucket_log;
- if (check_utf8(s->bucket_name_str.c_str(), entry.bucket.size()) != 0) {
+ if (check_utf8(s->bucket_name.c_str(), entry.bucket.size()) != 0) {
ldout(s->cct, 5) << "not logging op on bucket with non-utf8 name" << dendl;
return 0;
}
DECODE_START_LEGACY_COMPAT_LEN(8, 5, 5, p);
::decode(object_owner.id, p);
if (struct_v > 3)
- ::decode(bucket_owner, p);
+ ::decode(bucket_owner.id, p);
::decode(bucket, p);
::decode(time, p);
::decode(remote_addr, p);
}
return true;
}
+
+ /*
+ * The tenant_name is always returned on purpose. May be empty, of course.
+ */
+ static void parse_bucket(const string &bucket,
+ string &tenant_name, string &bucket_name)
+ {
+ int pos = bucket.find('/');
+ tenant_name = bucket.substr(0, pos);
+ bucket_name = bucket.substr(pos + 1);
+ }
};
#define META_LOG_OBJ_PREFIX "meta.log."
static string objexp_lock_name = "gc_process";
-int RGWObjectExpirer::init_bucket_info(const string& bucket_name,
- const string& bucket_id,
- RGWBucketInfo& bucket_info)
+int RGWObjectExpirer::init_bucket_info(const string& tenant_name,
+ const string& bucket_name,
+ const string& bucket_id,
+ RGWBucketInfo& bucket_info)
{
RGWObjectCtx obj_ctx(store);
- const string bucket_instance_id = bucket_name + ":" + bucket_id;
+ /*
+ * XXX Here's where it gets tricky. We went to all the trouble of
+ * punching the tenant through the objexp_hint_entry, but now we
+ * find that our instances do not actually have tenants. They are
+ * unique thanks to IDs. So the tenant string is not needed...
+ */
+ const string bucket_instance_id = bucket_name + ":" + bucket_id;
int ret = store->get_bucket_instance_info(obj_ctx, bucket_instance_id,
bucket_info, NULL, NULL);
-
return ret;
}
{
RGWBucketInfo bucket_info;
- int ret = init_bucket_info(hint.bucket_name, hint.bucket_id, bucket_info);
+ int ret = init_bucket_info(hint.tenant, hint.bucket_name,
+ hint.bucket_id, bucket_info);
if (-ENOENT == ret) {
ldout(store->ctx(), 15) << "NOTICE: cannot find bucket = " \
<< hint.bucket_name << ". The object must be already removed" << dendl;
protected:
RGWRados *store;
- int init_bucket_info(const string& bucket_name,
+ int init_bucket_info(const string& tenant_name,
+ const string& bucket_name,
const string& bucket_id,
RGWBucketInfo& bucket_info);
s->bucket_acl = new RGWAccessControlPolicy(s->cct);
}
- if (s->copy_source) { /* check if copy source is within the current domain */
- const char *src = s->copy_source;
- if (*src == '/')
- ++src;
- string copy_source_str(src);
-
- int pos = copy_source_str.find('/');
- if (pos > 0)
- copy_source_str = copy_source_str.substr(0, pos);
-
+ /* check if copy source is within the current domain */
+ if (!s->src_bucket_name.empty()) {
RGWBucketInfo source_info;
- ret = store->get_bucket_info(obj_ctx, copy_source_str, source_info, NULL);
+ ret = store->get_bucket_info(obj_ctx,
+ s->src_tenant_name, s->src_bucket_name, source_info, NULL);
if (ret == 0) {
string& region = source_info.region;
s->local_source = store->region.equals(region);
}
}
- if (!s->bucket_name_str.empty()) {
+ if (!s->bucket_name.empty()) {
s->bucket_exists = true;
if (s->bucket_instance_id.empty()) {
- ret = store->get_bucket_info(obj_ctx, s->bucket_name_str, s->bucket_info, NULL, &s->bucket_attrs);
+ ret = store->get_bucket_info(obj_ctx, s->bucket_tenant, s->bucket_name, s->bucket_info, NULL, &s->bucket_attrs);
} else {
ret = store->get_bucket_instance_info(obj_ctx, s->bucket_instance_id, s->bucket_info, NULL, &s->bucket_attrs);
}
if (ret < 0) {
if (ret != -ENOENT) {
- ldout(s->cct, 0) << "NOTICE: couldn't get bucket from bucket_name (name=" << s->bucket_name_str << ")" << dendl;
+ string bucket_log;
+ rgw_make_bucket_entry_name(s->bucket_tenant, s->bucket_name, bucket_log);
+ ldout(s->cct, 0) << "NOTICE: couldn't get bucket from bucket_name (name=" << bucket_log << ")" << dendl;
return ret;
}
s->bucket_exists = false;
RGWBucketInfo bucket_info;
map<string, bufferlist> bucket_attrs;
RGWObjectCtx obj_ctx(store);
- int r = store->get_bucket_info(obj_ctx, s->tenant, bucket_name, bucket_info, NULL, &bucket_attrs);
+ int r = store->get_bucket_info(obj_ctx, s->user.user_id.tenant, bucket_name,
+ bucket_info, NULL, &bucket_attrs);
if (r < 0) {
ldout(s->cct, 0) << "could not get bucket info for bucket=" << bucket_name << dendl;
return r;
if (!rgw_user_is_authenticated(s->user))
return -EACCES;
+ /* XXX: maybe we need to check ACLs here! */
+ // if ((s->perm_mask & RGW_PERM_WRITE) == 0) {
+ // return -EACCES;
+ // }
+
if (s->user.max_buckets) {
RGWUserBuckets buckets;
string marker;
bufferlist aclbl;
bufferlist corsbl;
bool existed;
- rgw_obj obj(store->zone.domain_root, s->bucket_name_str);
+ string bucket_name;
+ rgw_make_bucket_entry_name(s->bucket_tenant, s->bucket_name, bucket_name);
+ rgw_obj obj(store->zone.domain_root, bucket_name);
obj_version objv, *pobjv = NULL;
ret = get_params();
/* we need to make sure we read bucket info, it's not read before for this specific request */
RGWObjectCtx& obj_ctx = *static_cast<RGWObjectCtx *>(s->obj_ctx);
- ret = store->get_bucket_info(obj_ctx, s->bucket_name_str, s->bucket_info, NULL, &s->bucket_attrs);
+ ret = store->get_bucket_info(obj_ctx, s->bucket_tenant, s->bucket_name,
+ s->bucket_info, NULL, &s->bucket_attrs);
if (ret < 0 && ret != -ENOENT)
return;
s->bucket_exists = (ret != -ENOENT);
if (s->bucket_exists) {
string selected_placement_rule;
rgw_bucket bucket;
- ret = store->select_bucket_placement(s->user, region_name, placement_rule, s->bucket_name_str, bucket, &selected_placement_rule);
+ ret = store->select_bucket_placement(s->user, region_name, placement_rule,
+ s->bucket_tenant, s->bucket_name, bucket,
+ &selected_placement_rule);
if (selected_placement_rule != s->bucket_info.placement_rule) {
ret = -EEXIST;
return;
cors_config.encode(corsbl);
attrs[RGW_ATTR_CORS] = corsbl;
}
- s->bucket.name = s->bucket_name_str;
+ s->bucket.tenant = s->bucket_tenant; /* ignored if bucket exists */
+ s->bucket.name = s->bucket_name;
ret = store->create_bucket(s->user, s->bucket, region_name, placement_rule, attrs, info, pobjv,
&ep_objv, creation_time, pmaster_bucket, true);
/* continue if EEXIST and create_bucket will fail below. this way we can recover
ret = rgw_link_bucket(store, s->user.user_id, s->bucket, info.creation_time, false);
if (ret && !existed && ret != -EEXIST) { /* if it exists (or previously existed), don't remove it! */
- ret = rgw_unlink_bucket(store, s->user.user_id, s->bucket.name);
+ ret = rgw_unlink_bucket(store, s->user.user_id, s->bucket.tenant, s->bucket.name);
if (ret < 0) {
ldout(s->cct, 0) << "WARNING: failed to unlink bucket: ret=" << ret << dendl;
}
{
ret = -EINVAL;
- if (s->bucket_name_str.empty())
+ if (s->bucket_name.empty())
return;
RGWObjVersionTracker ot;
ret = store->delete_bucket(s->bucket, ot);
if (ret == 0) {
- ret = rgw_unlink_bucket(store, s->user.user_id, s->bucket.name, false);
+ ret = rgw_unlink_bucket(store, s->user.user_id, s->bucket.tenant, s->bucket.name, false);
if (ret < 0) {
ldout(s->cct, 0) << "WARNING: failed to unlink bucket: ret=" << ret << dendl;
}
if (!rgw_user_is_authenticated(s->user)) {
return -EACCES;
}
+ // if ((s->perm_mask & RGW_PERM_WRITE) == 0) {
+ // return -EACCES;
+ // }
return 0;
}
void RGWPutMetadataAccount::execute()
{
- rgw_obj obj;
map<string, bufferlist> attrs, orig_attrs, rmattrs;
RGWObjVersionTracker acct_op_tracker;
- /* Get the name of raw object which stores the metadata in its xattrs. */
- string buckets_obj_id;
- rgw_get_buckets_obj(s->user.user_id, buckets_obj_id);
- obj = rgw_obj(store->zone.user_uid_pool, buckets_obj_id);
-
ret = get_params();
if (ret < 0) {
return;
}
}
- ret = rgw_store_user_attrs(store, s->user.user_id, attrs, &rmattrs, &acct_op_tracker);
+ /* XXX tenant needed? */
+ ret = rgw_store_user_attrs(store, s->user.user_id.id, attrs, &rmattrs, &acct_op_tracker);
if (ret < 0) {
return;
}
params_str = url_src.substr(pos + 1);
}
-
string dec_src;
url_decode(name_str, dec_src);
string str(src);
- pos = str.find("/");
+ pos = str.find('/');
if (pos <= 0)
return false;
RGWObjectCtx& obj_ctx = *static_cast<RGWObjectCtx *>(s->obj_ctx);
- ret = store->get_bucket_info(obj_ctx, s->tenant, src_bucket_name, src_bucket_info, NULL, &src_attrs);
+ ret = store->get_bucket_info(obj_ctx, src_tenant_name, src_bucket_name,
+ src_bucket_info, NULL, &src_attrs);
if (ret < 0)
return ret;
dest_bucket_info = src_bucket_info;
dest_attrs = src_attrs;
} else {
- ret = store->get_bucket_info(obj_ctx, s->tenant, dest_bucket_name, dest_bucket_info, NULL, &dest_attrs);
+ ret = store->get_bucket_info(obj_ctx, dest_tenant_name, dest_bucket_name,
+ dest_bucket_info, NULL, &dest_attrs);
if (ret < 0)
return ret;
}
time_t *unmod_ptr;
int ret;
map<string, bufferlist> attrs;
- string src_bucket_name;
+ string src_tenant_name, src_bucket_name;
rgw_bucket src_bucket;
rgw_obj_key src_object;
- string dest_bucket_name;
+ string dest_tenant_name, dest_bucket_name;
rgw_bucket dest_bucket;
string dest_object;
time_t src_mtime;
delete_at = 0;
}
- static bool parse_copy_location(const string& src, string& bucket_name, rgw_obj_key& object);
+ static bool parse_copy_location(const string& src,
+ string& bucket_name,
+ rgw_obj_key& object);
virtual void init(RGWRados *store, struct req_state *s, RGWHandler *h) {
RGWOp::init(store, s, h);
int max_to_delete;
size_t len;
char *data;
- string bucket_name;
rgw_bucket bucket;
bool quiet;
bool status_dumped;
notify_oid.append(buf);
}
-int RGWRados::open_bucket_pool_ctx(const string& tenant, const string& bucket_name, const string& pool, librados::IoCtx& io_ctx)
+int RGWRados::open_bucket_pool_ctx(const string& pool, librados::IoCtx& io_ctx)
{
librados::Rados *rad = get_rados_handle();
int r = rad->ioctx_create(pool.c_str(), io_ctx);
int RGWRados::open_bucket_data_ctx(rgw_bucket& bucket, librados::IoCtx& data_ctx)
{
- int r = open_bucket_pool_ctx(bucket.name, bucket.data_pool, data_ctx);
+ int r = open_bucket_pool_ctx(bucket.data_pool, data_ctx);
if (r < 0)
return r;
int RGWRados::open_bucket_data_extra_ctx(rgw_bucket& bucket, librados::IoCtx& data_ctx)
{
string& pool = (!bucket.data_extra_pool.empty() ? bucket.data_extra_pool : bucket.data_pool);
- int r = open_bucket_pool_ctx(bucket.name, pool, data_ctx);
+ int r = open_bucket_pool_ctx(pool, data_ctx);
if (r < 0)
return r;
int RGWRados::open_bucket_index_ctx(rgw_bucket& bucket, librados::IoCtx& index_ctx)
{
- int r = open_bucket_pool_ctx(bucket.name, bucket.index_pool, index_ctx);
+ int r = open_bucket_pool_ctx(bucket.index_pool, index_ctx);
if (r < 0)
return r;
return sid % num_shards;
}
-static string objexp_hint_get_keyext(const string& bucket_name,
+static string objexp_hint_get_keyext(const string& tenant_name,
+ const string& bucket_name,
const string& bucket_id,
const rgw_obj_key& obj_key)
{
- return bucket_name + ":" + bucket_id + ":" + obj_key.name + ":" + obj_key.instance;
+ return tenant_name + ":" + bucket_name + ":" + bucket_id +
+ ":" + obj_key.name + ":" + obj_key.instance;
}
int RGWRados::objexp_hint_add(const utime_t& delete_at,
+ const string& tenant_name,
const string& bucket_name,
const string& bucket_id,
const rgw_obj_key& obj_key)
{
- const string keyext = objexp_hint_get_keyext(bucket_name,
+ const string keyext = objexp_hint_get_keyext(tenant_name, bucket_name,
bucket_id, obj_key);
objexp_hint_entry he = {
+ .tenant = tenant_name,
.bucket_name = bucket_name,
.bucket_id = bucket_id,
.obj_key = obj_key,
string selected_placement_rule;
for (int i = 0; i < MAX_CREATE_RETRIES; i++) {
int ret = 0;
- ret = select_bucket_placement(owner, region_name, placement_rule, bucket.name, bucket, &selected_placement_rule);
+ ret = select_bucket_placement(owner, region_name, placement_rule,
+ bucket.tenant, bucket.name, bucket,
+ &selected_placement_rule);
if (ret < 0)
return ret;
bufferlist bl;
bucket.bucket_id = pmaster_bucket->bucket_id;
}
- string dir_oid = dir_oid_prefix;
- dir_oid.append(bucket.marker);
-
r = init_bucket_index(bucket, bucket_index_max_shards);
if (r < 0)
return r;
RGWObjVersionTracker instance_ver = info.objv_tracker;
info.objv_tracker.clear();
RGWObjectCtx obj_ctx(this);
- r = get_bucket_info(obj_ctx, bucket.name, info, NULL, NULL);
+ r = get_bucket_info(obj_ctx, bucket.tenant, bucket.name, info, NULL, NULL);
if (r < 0) {
if (r == -ENOENT) {
continue;
}
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)
+ const string& tenant_name, 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 (pselected_rule)
*pselected_rule = rule;
- return set_bucket_location_by_rule(rule, bucket_name, bucket);
+ return set_bucket_location_by_rule(rule, tenant_name, bucket_name, bucket);
}
-int RGWRados::set_bucket_location_by_rule(const string& location_rule, const std::string& bucket_name, rgw_bucket& bucket)
+int RGWRados::set_bucket_location_by_rule(const string& location_rule, const string& tenant_name, const string& bucket_name, rgw_bucket& bucket)
{
+ bucket.tenant = tenant_name;
bucket.name = bucket_name;
if (location_rule.empty()) {
/* we can only reach here if we're trying to set a bucket location from a bucket
* created on a different zone, using a legacy / default pool configuration
*/
- return select_legacy_bucket_placement(bucket_name, bucket);
+ return select_legacy_bucket_placement(tenant_name, bucket_name, bucket);
}
/*
bucket.data_extra_pool = placement_info.data_extra_pool;
bucket.index_pool = placement_info.index_pool;
- return 0;
+ // XXX The select_legacy_bucket_placement() does this, but here we don't?
+ // bucket.tenant = tenant_name;
+ // bucket.name = bucket_name;
+ 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)
+ const string& tenant_name, const string& bucket_name, rgw_bucket& bucket,
+ string *pselected_rule)
{
if (!zone.placement_pools.empty()) {
- return select_new_bucket_location(user_info, region_name, placement_rule, bucket_name, bucket, pselected_rule);
+ return select_new_bucket_location(user_info, region_name, placement_rule,
+ tenant_name, bucket_name, bucket, pselected_rule);
}
if (pselected_rule)
pselected_rule->clear();
- return select_legacy_bucket_placement(bucket_name, bucket);
+ return select_legacy_bucket_placement(tenant_name, bucket_name, bucket);
}
-int RGWRados::select_legacy_bucket_placement(const string& bucket_name, rgw_bucket& bucket)
+int RGWRados::select_legacy_bucket_placement(const string& tenant_name, const string& bucket_name, rgw_bucket& bucket)
{
bufferlist map_bl;
map<string, bufferlist> m;
}
bucket.data_pool = pool_name;
bucket.index_pool = pool_name;
+ bucket.tenant = tenant_name;
bucket.name = bucket_name;
return 0;
rgw_obj_key obj_key;
obj.get_index_key(&obj_key);
- r = store->objexp_hint_add(utime_t(meta.delete_at, 0), bucket.name, bucket.bucket_id, obj_key);
+ r = store->objexp_hint_add(utime_t(meta.delete_at, 0),
+ bucket.tenant, bucket.name, bucket.bucket_id, obj_key);
if (r < 0) {
ldout(store->ctx(), 0) << "ERROR: objexp_hint_add() returned r=" << r << ", object will not get removed" << dendl;
/* ignoring error, nothing we can do at this point */
}
} while (is_truncated);
- r = rgw_bucket_delete_bucket_obj(this, bucket.name, objv_tracker);
+ r = rgw_bucket_delete_bucket_obj(this, bucket.tenant, bucket.name, objv_tracker);
if (r < 0)
return r;
RGWBucketInfo info;
map<string, bufferlist> attrs;
RGWObjectCtx obj_ctx(this);
- int r = get_bucket_info(obj_ctx, bucket.name, info, NULL, &attrs);
+ int r = get_bucket_info(obj_ctx, bucket.tenant, bucket.name, info, NULL, &attrs);
if (r < 0) {
ldout(cct, 0) << "NOTICE: get_bucket_info on bucket=" << bucket.name << " returned err=" << r << dendl;
return r;
RGWBucketInfo info;
map<string, bufferlist> attrs;
RGWObjectCtx obj_ctx(this);
- int r = get_bucket_info(obj_ctx, bucket.name, info, NULL, &attrs);
+ int r = get_bucket_info(obj_ctx, bucket.tenant, bucket.name, info, NULL, &attrs);
if (r < 0) {
ldout(cct, 0) << "NOTICE: get_bucket_info on bucket=" << bucket.name << " returned err=" << r << ", skipping bucket" << dendl;
ret = r;
{
RGWBucketInfo bucket_info;
RGWObjectCtx obj_ctx(this);
- int ret = get_bucket_info(obj_ctx, bucket.name, bucket_info, NULL);
+ int ret = get_bucket_info(obj_ctx, bucket.tenant, bucket.name, bucket_info, NULL);
if (ret < 0) {
return ret;
}
rgw_obj_key obj_key;
obj.get_index_key(&obj_key);
- objexp_hint_add(ts, bucket.name, bucket.bucket_id, obj_key);
+ objexp_hint_add(ts, bucket.tenant, bucket.name, bucket.bucket_id, obj_key);
} catch (buffer::error& err) {
ldout(cct, 0) << "ERROR: failed to decode " RGW_ATTR_DELETE_AT << " attr" << dendl;
}
* (if get_data==true) length of read data,
* (if get_data==false) length of the object
*/
+// P3 XXX get_data is not seen used anywhere.
int RGWRados::Object::Read::prepare(int64_t *pofs, int64_t *pend)
{
RGWRados *store = source->get_store();
return 0;
}
-int RGWRados::get_bucket_entrypoint_info(RGWObjectCtx& obj_ctx, const string& bucket_name,
+int RGWRados::get_bucket_entrypoint_info(RGWObjectCtx& obj_ctx,
+ const string& tenant_name,
+ const string& bucket_name,
RGWBucketEntryPoint& entry_point,
RGWObjVersionTracker *objv_tracker,
time_t *pmtime,
rgw_cache_entry_info *cache_info)
{
bufferlist bl;
+ string bucket_entry;
- int ret = rgw_get_system_obj(this, obj_ctx, zone.domain_root, bucket_name, bl, objv_tracker, pmtime, pattrs, cache_info);
+ rgw_make_bucket_entry_name(tenant_name, bucket_name, bucket_entry);
+ int ret = rgw_get_system_obj(this, obj_ctx, zone.domain_root, bucket_entry, bl, objv_tracker, pmtime, pattrs, cache_info);
if (ret < 0) {
return ret;
}
return 0;
}
-int RGWRados::convert_old_bucket_info(RGWObjectCtx& obj_ctx, string& bucket_name)
+int RGWRados::convert_old_bucket_info(RGWObjectCtx& obj_ctx,
+ const string& tenant_name,
+ const string& bucket_name)
{
RGWBucketEntryPoint entry_point;
time_t ep_mtime;
ldout(cct, 10) << "RGWRados::convert_old_bucket_info(): bucket=" << bucket_name << dendl;
- int ret = get_bucket_entrypoint_info(obj_ctx, bucket_name, entry_point, &ot, &ep_mtime, &attrs);
+ int ret = get_bucket_entrypoint_info(obj_ctx, tenant_name, bucket_name, entry_point, &ot, &ep_mtime, &attrs);
if (ret < 0) {
ldout(cct, 0) << "ERROR: get_bucket_entrypont_info() returned " << ret << " bucket=" << bucket_name << dendl;
return ret;
return 0;
}
-struct bucket_info_entry {
- RGWBucketInfo info;
- time_t mtime;
- map<string, bufferlist> attrs;
-};
-
-static RGWChainedCacheImpl<bucket_info_entry> binfo_cache;
-
-int RGWRados::get_bucket_info(RGWObjectCtx& obj_ctx, const string& tenant, const string& bucket_name, RGWBucketInfo& info,
+int RGWRados::get_bucket_info(RGWObjectCtx& obj_ctx,
+ const string& tenant, const string& bucket_name, RGWBucketInfo& info,
time_t *pmtime, map<string, bufferlist> *pattrs)
{
bucket_info_entry e;
- if (binfo_cache.find(bucket_name, &e)) {
+ string bucket_entry;
+ rgw_make_bucket_entry_name(tenant, bucket_name, bucket_entry);
+
+ if (binfo_cache.find(bucket_entry, &e)) {
info = e.info;
if (pattrs)
*pattrs = e.attrs;
rgw_cache_entry_info entry_cache_info;
int ret = get_bucket_entrypoint_info(obj_ctx, tenant, bucket_name, entry_point, &ot, &ep_mtime, pattrs, &entry_cache_info);
if (ret < 0) {
- info.bucket.name = bucket_name; /* only init this field */
+ /* only init these fields */
+ info.bucket.tenant = tenant;
+ info.bucket.name = bucket_name;
return ret;
}
e.info.ep_objv = ot.read_version;
info = e.info;
if (ret < 0) {
+ info.bucket.tenant = tenant;
info.bucket.name = bucket_name;
+ // XXX and why return anything in case of an error anyway?
return ret;
}
/* chain to both bucket entry point and bucket instance */
- if (!binfo_cache.put(this, bucket_name, &e, cache_info_entries)) {
+ if (!binfo_cache.put(this, bucket_entry, &e, cache_info_entries)) {
ldout(cct, 20) << "couldn't put binfo cache entry, might have raced with data changes" << dendl;
}
return 0;
}
-int RGWRados::put_bucket_entrypoint_info(const string& tenant, const string& bucket_name, RGWBucketEntryPoint& entry_point,
+int RGWRados::put_bucket_entrypoint_info(const string& tenant_name, const string& bucket_name, RGWBucketEntryPoint& entry_point,
bool exclusive, RGWObjVersionTracker& objv_tracker, time_t mtime,
map<string, bufferlist> *pattrs)
{
bufferlist epbl;
::encode(entry_point, epbl);
- return rgw_bucket_store_info(this, bucket_name, epbl, exclusive, pattrs, &objv_tracker, mtime);
+ string bucket_entry;
+ rgw_make_bucket_entry_name(tenant_name, bucket_name, bucket_entry);
+ return rgw_bucket_store_info(this, bucket_entry, epbl, exclusive, pattrs, &objv_tracker, mtime);
}
int RGWRados::put_bucket_instance_info(RGWBucketInfo& info, bool exclusive,
*pep_objv = ot.write_version;
}
}
- ret = put_bucket_entrypoint_info(info.bucket.name, entry_point, exclusive, ot, mtime, NULL);
+ ret = put_bucket_entrypoint_info(info.bucket.tenant, info.bucket.name, entry_point, exclusive, ot, mtime, NULL);
if (ret < 0)
return ret;
prepend_bucket_marker(bucket, obj.get_object(), oid);
const string& loc = obj.get_loc();
if (!loc.empty()) {
- prepend_bucket_marker(bucket, obj.get_loc(), locator);
+ prepend_bucket_marker(bucket, obj.get_loc(), locator); // XXX get_loc twice
} else {
locator.clear();
}
WRITE_CLASS_ENCODER(RGWRegionMap)
struct objexp_hint_entry {
+ string tenant;
string bucket_name;
string bucket_id;
rgw_obj_key obj_key;
utime_t exp_time;
void encode(bufferlist& bl) const {
- ENCODE_START(1, 1, bl);
+ ENCODE_START(2, 1, bl);
::encode(bucket_name, bl);
::encode(bucket_id, bl);
::encode(obj_key, bl);
::encode(exp_time, bl);
+ ::encode(tenant, bl);
ENCODE_FINISH(bl);
}
void decode(bufferlist::iterator& bl) {
- DECODE_START(1, bl);
+ // XXX Do we want DECODE_START_LEGACY_COMPAT_LEN(2, 1, 1, bl); ?
+ DECODE_START(2, bl);
::decode(bucket_name, bl);
::decode(bucket_id, bl);
::decode(obj_key, bl);
::decode(exp_time, bl);
+ if (struct_v >= 2) {
+ ::decode(tenant, bl);
+ } else {
+ tenant.clear();
+ }
DECODE_FINISH(bl);
}
};
int open_gc_pool_ctx();
int open_objexp_pool_ctx();
- int open_bucket_pool_ctx(const string& bucket_name, const string& pool, librados::IoCtx& io_ctx);
+ int open_bucket_pool_ctx(const string& pool, librados::IoCtx& io_ctx);
int open_bucket_index_ctx(rgw_bucket& bucket, librados::IoCtx& index_ctx);
int open_bucket_data_ctx(rgw_bucket& bucket, librados::IoCtx& io_ctx);
int open_bucket_data_extra_ctx(rgw_bucket& bucket, librados::IoCtx& io_ctx);
* returns 0 on success, -ERR# otherwise.
*/
virtual int init_bucket_index(rgw_bucket& bucket, int num_shards);
- 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_legacy_bucket_placement(const string& bucket_name, rgw_bucket& bucket);
+ int select_bucket_placement(RGWUserInfo& user_info, const string& region_name, const string& rule,
+ const string& tenant_name, const string& bucket_name, rgw_bucket& bucket, string *pselected_rule);
+ int select_legacy_bucket_placement(const string& tenant_name, const string& bucket_name, rgw_bucket& bucket);
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);
+ const string& tenant_name, const string& bucket_name, rgw_bucket& bucket, string *pselected_rule);
+ int set_bucket_location_by_rule(const string& location_rule, const string& tenant_name, const string& bucket_name, rgw_bucket& bucket);
virtual int create_bucket(RGWUserInfo& owner, rgw_bucket& bucket,
const string& region_name,
const string& placement_rule,
void get_bucket_instance_entry(rgw_bucket& bucket, string& entry);
void get_bucket_meta_oid(rgw_bucket& bucket, string& oid);
- int put_bucket_entrypoint_info(const string& bucket_name, RGWBucketEntryPoint& entry_point, bool exclusive, RGWObjVersionTracker& objv_tracker, time_t mtime,
+ int put_bucket_entrypoint_info(const string& tenant_name, const string& bucket_name, RGWBucketEntryPoint& entry_point,
+ bool exclusive, RGWObjVersionTracker& objv_tracker, time_t mtime,
map<string, bufferlist> *pattrs);
int put_bucket_instance_info(RGWBucketInfo& info, bool exclusive, time_t mtime, map<string, bufferlist> *pattrs);
- int get_bucket_entrypoint_info(RGWObjectCtx& obj_ctx, const string& tenant, const string& bucket_name, RGWBucketEntryPoint& entry_point, RGWObjVersionTracker *objv_tracker, time_t *pmtime,
- map<string, bufferlist> *pattrs, rgw_cache_entry_info *cache_info = NULL);
+ int get_bucket_entrypoint_info(RGWObjectCtx& obj_ctx, const string& tenant_name, const string& bucket_name,
+ RGWBucketEntryPoint& entry_point, RGWObjVersionTracker *objv_tracker,
+ time_t *pmtime, map<string, bufferlist> *pattrs, rgw_cache_entry_info *cache_info = NULL);
int get_bucket_instance_info(RGWObjectCtx& obj_ctx, const string& meta_key, RGWBucketInfo& info, time_t *pmtime, map<string, bufferlist> *pattrs);
int get_bucket_instance_info(RGWObjectCtx& obj_ctx, rgw_bucket& bucket, RGWBucketInfo& info, time_t *pmtime, map<string, bufferlist> *pattrs);
int get_bucket_instance_from_oid(RGWObjectCtx& obj_ctx, string& oid, RGWBucketInfo& info, time_t *pmtime, map<string, bufferlist> *pattrs,
rgw_cache_entry_info *cache_info = NULL);
- int convert_old_bucket_info(RGWObjectCtx& obj_ctx, string& bucket_name);
- virtual int get_bucket_info(RGWObjectCtx& obj_ctx, const string& bucket_name, RGWBucketInfo& info,
+ int convert_old_bucket_info(RGWObjectCtx& obj_ctx, const string& tenant_name, const string& bucket_name);
+ static void make_bucket_entry_name(const string& tenant_name, const string& bucket_name, string& bucket_entry);
+ virtual int get_bucket_info(RGWObjectCtx& obj_ctx,
+ const string& tenant_name, const string& bucket_name,
+ RGWBucketInfo& info,
time_t *pmtime, map<string, bufferlist> *pattrs = NULL);
virtual int put_linked_bucket_info(RGWBucketInfo& info, bool exclusive, time_t mtime, obj_version *pep_objv,
map<string, bufferlist> *pattrs, bool create_entry_point);
void objexp_get_shard(int shard_num,
string& shard); /* out */
int objexp_hint_add(const utime_t& delete_at,
+ const string& tenant_name,
const string& bucket_name,
const string& bucket_id,
const rgw_obj_key& obj_key);
{
int expose_bucket = g_conf->rgw_expose_bucket;
if (expose_bucket) {
- if (!s->bucket_name_str.empty()) {
+ if (!s->bucket_name.empty()) {
string b;
- url_encode(s->bucket_name_str, b);
+ if (!s->bucket_tenant.empty()) {
+ string g = s->bucket_tenant + "/" + s->bucket_name;
+ url_encode(g, b);
+ } else {
+ url_encode(s->bucket_name, b);
+ }
s->cio->print("Bucket: %s\r\n", b.c_str());
}
}
string server = s->info.env->get("SERVER_NAME", "<SERVER_NAME>");
location.append(server);
location += "/";
- if (!s->bucket_name_str.empty()) {
- location += s->bucket_name_str;
+ if (!s->bucket_name.empty()) {
+ if (!s->bucket_tenant.empty()) {
+ location += s->bucket_tenant;
+ location += ":";
+ }
+ location += s->bucket_name;
location += "/";
if (!s->object.empty()) {
location += s->object.name;
int RGWDeleteMultiObj_ObjStore::get_params()
{
- bucket_name = s->bucket_name_str;
- if (bucket_name.empty()) {
+ if (s->bucket_name.empty()) {
ret = -EINVAL;
return ret;
}
return 0;
}
+int RGWHandler_ObjStore::validate_tenant_name(string const& t)
+{
+ struct tench {
+ static bool is_good(char ch) {
+ return isalnum(ch) || ch == '_';
+ }
+ };
+ std::string::const_iterator it = std::find_if(t.begin(), t.end(), tench::is_good);
+ return (it == t.end())? 0: -ERR_INVALID_BUCKET_NAME;
+}
+
// This function enforces Amazon's spec for bucket names.
// (The requirements, not the recommendations.)
int RGWHandler_ObjStore::validate_bucket_name(const string& bucket)
string encoded_bucket = "/";
encoded_bucket.append(subdomain);
if (s->info.request_uri[0] != '/')
- encoded_bucket.append("/'");
+ encoded_bucket.append("/'"); // XXX What in the world is this apostrophe?
encoded_bucket.append(s->info.request_uri);
s->info.request_uri = encoded_bucket;
}
virtual RGWOp *op_copy() { return NULL; }
virtual RGWOp *op_options() { return NULL; }
+ virtual int validate_tenant_name(const string& bucket);
virtual int validate_bucket_name(const string& bucket);
virtual int validate_object_name(const string& object);
}
void RGWOp_BILog_List::execute() {
- string bucket_name = s->info.args.get("bucket"),
+ string tenant_name = s->info.args.get("tenant"),
+ bucket_name = s->info.args.get("bucket"),
marker = s->info.args.get("marker"),
max_entries_str = s->info.args.get("max-entries"),
bucket_instance = s->info.args.get("bucket-instance");
return;
}
} else { /* !bucket_name.empty() */
- http_ret = store->get_bucket_info(obj_ctx, bucket_name, bucket_info, NULL, NULL);
+ http_ret = store->get_bucket_info(obj_ctx, tenant_name, bucket_name, bucket_info, NULL, NULL);
if (http_ret < 0) {
dout(5) << "could not get bucket info for bucket=" << bucket_name << dendl;
return;
}
void RGWOp_BILog_Info::execute() {
- string bucket_name = s->info.args.get("bucket"),
+ string tenant_name = s->info.args.get("tenant"),
+ bucket_name = s->info.args.get("bucket"),
bucket_instance = s->info.args.get("bucket-instance");
RGWBucketInfo bucket_info;
return;
}
} else { /* !bucket_name.empty() */
- http_ret = store->get_bucket_info(obj_ctx, bucket_name, bucket_info, NULL, NULL);
+ http_ret = store->get_bucket_info(obj_ctx, tenant_name, bucket_name, bucket_info, NULL, NULL);
if (http_ret < 0) {
dout(5) << "could not get bucket info for bucket=" << bucket_name << dendl;
return;
}
void RGWOp_BILog_Delete::execute() {
- string bucket_name = s->info.args.get("bucket"),
+ string tenant_name = s->info.args.get("tenant"),
+ bucket_name = s->info.args.get("bucket"),
start_marker = s->info.args.get("start-marker"),
end_marker = s->info.args.get("end-marker"),
bucket_instance = s->info.args.get("bucket-instance");
return;
}
} else { /* !bucket_name.empty() */
- http_ret = store->get_bucket_info(obj_ctx, bucket_name, bucket_info, NULL, NULL);
+ http_ret = store->get_bucket_info(obj_ctx, tenant_name, bucket_name, bucket_info, NULL, NULL);
if (http_ret < 0) {
dout(5) << "could not get bucket info for bucket=" << bucket_name << dendl;
return;
string key = s->info.args.get("key", &exists);
string section;
- if (!s->bucket_name_str.empty()) {
- section = s->bucket_name_str;
+ if (!s->bucket_name.empty()) {
+ section = s->bucket_name;
} else {
section = key;
key.clear();
{
s->formatter->open_object_section_in_ns("ListVersionsResult",
"http://s3.amazonaws.com/doc/2006-03-01/");
- s->formatter->dump_string("Name", s->bucket_name_str);
+ if (!s->bucket_tenant.empty())
+ s->formatter->dump_string("Tenant", s->bucket_tenant);
+ s->formatter->dump_string("Name", s->bucket_name);
s->formatter->dump_string("Prefix", prefix);
s->formatter->dump_string("KeyMarker", marker.name);
if (is_truncated && !next_marker.empty())
s->formatter->open_object_section_in_ns("ListBucketResult",
"http://s3.amazonaws.com/doc/2006-03-01/");
- s->formatter->dump_string("Name", s->bucket_name_str);
+ if (!s->bucket_tenant.empty())
+ s->formatter->dump_string("Tenant", s->bucket_tenant);
+ s->formatter->dump_string("Name", s->bucket_name);
s->formatter->dump_string("Prefix", prefix);
s->formatter->dump_string("Marker", marker.name);
if (is_truncated && !next_marker.empty())
part_str("success_action_redirect", &redirect);
+ string tenant;
string bucket;
string key;
string etag_str = "\"";
string etag_url;
- url_encode(s->bucket_name_str, bucket);
+ url_encode(s->bucket_tenant, tenant); /* surely overkill, but cheap */
+ url_encode(s->bucket_name, bucket);
url_encode(s->object.name, key);
url_encode(etag_str, etag_url);
- redirect.append("?bucket=");
- redirect.append(bucket);
+ if (!s->bucket_tenant.empty()) {
+ /*
+ * What we really would like is to quaily the bucket name, so
+ * that the client could simply copy it and paste into next request.
+ * Unfortunately, in S3 we cannot know if the client will decide
+ * to come through DNS, with "bucket.tenant" sytanx, or through
+ * URL with "tenant\bucket" syntax. Therefore, we provide the
+ * tenant separately.
+ */
+ redirect.append("?tenant=");
+ redirect.append(tenant);
+ redirect.append("&bucket=");
+ redirect.append(bucket);
+ } else {
+ redirect.append("?bucket=");
+ redirect.append(bucket);
+ }
redirect.append("&key=");
redirect.append(key);
redirect.append("&etag=");
s->formatter->open_object_section("PostResponse");
if (g_conf->rgw_dns_name.length())
s->formatter->dump_format("Location", "%s/%s", s->info.script_uri.c_str(), s->object.name.c_str());
- s->formatter->dump_string("Bucket", s->bucket_name_str);
+ if (!s->bucket_tenant.empty())
+ s->formatter->dump_string("Tenant", s->bucket_tenant);
+ s->formatter->dump_string("Bucket", s->bucket_name);
s->formatter->dump_string("Key", s->object.name);
s->formatter->close_section();
}
if_match = s->info.env->get("HTTP_X_AMZ_COPY_IF_MATCH");
if_nomatch = s->info.env->get("HTTP_X_AMZ_COPY_IF_NONE_MATCH");
+ src_tenant_name = s->src_tenant_name;
src_bucket_name = s->src_bucket_name;
src_object = s->src_object;
+ dest_tenant_name = s->bucket.tenant;
dest_bucket_name = s->bucket.name;
dest_object = s->object.name;
}
if (source_zone.empty() &&
+ (dest_tenant_name.compare(src_tenant_name) == 0) &&
(dest_bucket_name.compare(src_bucket_name) == 0) &&
(dest_object.compare(src_object.name) == 0) &&
src_object.instance.empty() &&
dump_start(s);
s->formatter->open_object_section_in_ns("InitiateMultipartUploadResult",
"http://s3.amazonaws.com/doc/2006-03-01/");
- s->formatter->dump_string("Bucket", s->bucket_name_str);
+ if (!s->bucket_tenant.empty())
+ s->formatter->dump_string("Tenant", s->bucket_tenant);
+ s->formatter->dump_string("Bucket", s->bucket_name);
s->formatter->dump_string("Key", s->object.name);
s->formatter->dump_string("UploadId", upload_id);
s->formatter->close_section();
dump_start(s);
s->formatter->open_object_section_in_ns("CompleteMultipartUploadResult",
"http://s3.amazonaws.com/doc/2006-03-01/");
- if (s->info.domain.length())
- s->formatter->dump_format("Location", "%s.%s", s->bucket_name_str.c_str(), s->info.domain.c_str());
- s->formatter->dump_string("Bucket", s->bucket_name_str);
+ if (!s->bucket_tenant.empty()) {
+ if (s->info.domain.length()) {
+ s->formatter->dump_format("Location", "%s.%s.%s",
+ s->bucket_name.c_str(),
+ s->bucket_tenant.c_str(),
+ s->info.domain.c_str());
+ }
+ s->formatter->dump_string("Tenant", s->bucket_tenant);
+ } else {
+ if (s->info.domain.length()) {
+ s->formatter->dump_format("Location", "%s.%s",
+ s->bucket_name.c_str(),
+ s->info.domain.c_str());
+ }
+ }
+ s->formatter->dump_string("Bucket", s->bucket_name);
s->formatter->dump_string("Key", s->object.name);
s->formatter->dump_string("ETag", etag);
s->formatter->close_section();
if (test_iter != parts.rend()) {
cur_max = test_iter->first;
}
- s->formatter->dump_string("Bucket", s->bucket_name_str);
+ if (!s->bucket_tenant.empty())
+ s->formatter->dump_string("Tenant", s->bucket_tenant);
+ s->formatter->dump_string("Bucket", s->bucket_name);
s->formatter->dump_string("Key", s->object.name);
s->formatter->dump_string("UploadId", upload_id);
s->formatter->dump_string("StorageClass", "STANDARD");
return;
s->formatter->open_object_section("ListMultipartUploadsResult");
- s->formatter->dump_string("Bucket", s->bucket_name_str);
+ if (!s->bucket_tenant.empty())
+ s->formatter->dump_string("Tenant", s->bucket_tenant);
+ s->formatter->dump_string("Bucket", s->bucket_name);
if (!prefix.empty())
s->formatter->dump_string("ListMultipartUploadsResult.Prefix", prefix);
string& key_marker = marker.get_key();
if (is_acl_op()) {
return new RGWPutACLs_ObjStore_S3;
}
- if (!s->copy_source)
+ if (s->src_bucket_name.empty())
return new RGWPutObj_ObjStore_S3;
else
return new RGWCopyObj_ObjStore_S3;
first = req;
}
- if (s->bucket_name_str.empty()) {
- s->bucket_name_str = first;
+ /*
+ * XXX The intent of the check for empty is apparently to let the bucket
+ * name from DNS to be set ahead. However, we currently take the DNS
+ * bucket and re-insert it into URL in rgw_rest.cc:RGWREST::preprocess().
+ * So, this check is meaningless.
+ *
+ * Rather than dropping this, the code needs to be changed into putting
+ * the bucket (and its tenant) from DNS and Host: header (HTTP_HOST)
+ * into req_status.bucket_name directly.
+ */
+ if (s->bucket_name.empty()) {
+ rgw_parse_url_bucket(first, s->bucket_tenant, s->bucket_name);
+ if (s->bucket_tenant.empty())
+ s->bucket_tenant = s->user.user_id.tenant;
if (pos >= 0) {
string encoded_obj_str = req.substr(pos+1);
int RGWHandler_ObjStore_S3::init(RGWRados *store, struct req_state *s, RGWClientIO *cio)
{
- dout(10) << "s->object=" << (!s->object.empty() ? s->object : rgw_obj_key("<NULL>")) << " s->bucket=" << (!s->bucket_name_str.empty() ? s->bucket_name_str : "<NULL>") << dendl;
+ string bucket_log;
+ rgw_make_bucket_entry_name(s->bucket_tenant, s->bucket_name, bucket_log);
+ dout(10) << "s->object=" << (!s->object.empty() ? s->object : rgw_obj_key("<NULL>")) << " s->bucket=" << bucket_log << dendl;
+ int ret;
+ ret = validate_tenant_name(s->bucket_tenant);
+ if (ret)
+ return ret;
bool relaxed_names = s->cct->_conf->rgw_relaxed_s3_bucket_names;
- int ret = validate_bucket_name(s->bucket_name_str, relaxed_names);
+ ret = validate_bucket_name(s->bucket_name, relaxed_names);
if (ret)
return ret;
ret = validate_object_name(s->object.name);
s->has_acl_header = s->info.env->exists_prefix("HTTP_X_AMZ_GRANT");
- s->copy_source = s->info.env->get("HTTP_X_AMZ_COPY_SOURCE");
- if (s->copy_source) {
- ret = RGWCopyObj::parse_copy_location(s->copy_source, s->src_bucket_name, s->src_object);
+ const char *copy_source = s->info.env->get("HTTP_X_AMZ_COPY_SOURCE");
+ if (copy_source) {
+ string src_bucket_str;
+ ret = RGWCopyObj::parse_copy_location(copy_source, src_bucket_str, s->src_object);
if (!ret) {
ldout(s->cct, 0) << "failed to parse copy location" << dendl;
- return -EINVAL;
+ return -EINVAL; // XXX why not -ERR_INVALID_BUCKET_NAME or -ERR_BAD_URL?
}
+ rgw_parse_url_bucket(src_bucket_str, s->src_tenant_name, s->src_bucket_name);
+ if (s->src_tenant_name.empty())
+ s->src_tenant_name = s->user.user_id.tenant;
}
s->dialect = "s3";
} /* if keystone_result < 0 */
// populate the owner info
- s->tenant = s->user.user_id.tenant;
s->owner.set_id(s->user.user_id);
s->owner.set_name(s->user.display_name);
if (ret < 0)
return NULL;
- if (s->bucket_name_str.empty())
+ if (s->bucket_name.empty())
return new RGWHandler_ObjStore_Service_S3;
if (s->object.empty())
if_match = s->info.env->get("HTTP_COPY_IF_MATCH");
if_nomatch = s->info.env->get("HTTP_COPY_IF_NONE_MATCH");
+ /* XXX why copy this? just use req_state in rgw_op.cc:verify_permission */
+ src_tenant_name = s->src_tenant_name;
src_bucket_name = s->src_bucket_name;
src_object = s->src_object;
- dest_bucket_name = s->bucket_name_str;
+ dest_tenant_name = s->bucket_tenant;
+ dest_bucket_name = s->bucket_name;
dest_object = s->object.name;
const char * const fresh_meta = s->info.env->get("HTTP_X_FRESH_METADATA");
/* Dump X-Copied-From-Account */
string account_name;
- url_encode(s->user.user_id, account_name);
+ url_encode(s->user.user_id.id, account_name); // XXX tenant
s->cio->print("X-Copied-From-Account: %s\r\n", account_name.c_str());
/* Dump X-Copied-From-Last-Modified. */
if (first.size() == 0)
return 0;
- s->bucket_name_str = first;
+ s->info.effective_uri = "/" + first;
- s->info.effective_uri = "/" + s->bucket_name_str;
+ /* XXX Temporarily not parsing URL until Auth puts something in there. */
+ s->bucket_tenant = s->user.user_id.tenant;
+ s->bucket_name = first;
if (req.size()) {
s->object = rgw_obj_key(req, s->info.env->get("HTTP_X_OBJECT_VERSION_ID", "")); /* rgw swift extension */
int RGWHandler_ObjStore_SWIFT::init(RGWRados *store, struct req_state *s, RGWClientIO *cio)
{
- dout(10) << "s->object=" << (!s->object.empty() ? s->object : rgw_obj_key("<NULL>")) << " s->bucket=" << (!s->bucket_name_str.empty() ? s->bucket_name_str : "<NULL>") << dendl;
+ string bucket_log;
+ rgw_make_bucket_entry_name(s->bucket_tenant, s->bucket_name, bucket_log);
+ dout(10) << "s->object=" << (!s->object.empty() ? s->object : rgw_obj_key("<NULL>")) << " s->bucket=" << bucket_log << dendl;
- int ret = validate_bucket_name(s->bucket_name_str.c_str());
+ int ret;
+ ret = validate_tenant_name(s->bucket_tenant);
+ if (ret)
+ return ret;
+ /* XXX The c_str is redundant here, isn't it? We do one inside. */
+ ret = validate_bucket_name(s->bucket_name.c_str());
if (ret)
return ret;
ret = validate_object_name(s->object.name);
if (ret)
return ret;
- s->copy_source = s->info.env->get("HTTP_X_COPY_FROM");
- if (s->copy_source) {
- bool result = RGWCopyObj::parse_copy_location(s->copy_source, s->src_bucket_name, s->src_object);
+ const char *copy_source = s->info.env->get("HTTP_X_COPY_FROM");
+ if (copy_source) {
+ bool result = RGWCopyObj::parse_copy_location(copy_source, s->src_bucket_name, s->src_object);
if (!result)
return -ERR_BAD_URL;
+ s->src_tenant_name = s->user.user_id.tenant;
}
s->dialect = "swift";
if (!req_dest)
return -ERR_BAD_URL;
- string dest_bucket_name;
+ string dest_tenant_name, dest_bucket_name;
rgw_obj_key dest_obj_key;
bool result = RGWCopyObj::parse_copy_location(req_dest, dest_bucket_name, dest_obj_key);
if (!result)
return -ERR_BAD_URL;
+ dest_tenant_name = s->user.user_id.tenant;
string dest_object = dest_obj_key.name;
- if (dest_bucket_name != s->bucket_name_str) {
+ if (dest_bucket_name != s->bucket_name) {
ret = validate_bucket_name(dest_bucket_name.c_str());
if (ret < 0)
return ret;
}
+ ret = validate_tenant_name(dest_tenant_name);
+ if (ret < 0)
+ return ret;
+
/* convert COPY operation into PUT */
- s->src_bucket_name = s->bucket_name_str;
+ s->src_tenant_name = s->bucket_tenant;
+ s->src_bucket_name = s->bucket_name;
s->src_object = s->object;
- s->bucket_name_str = dest_bucket_name;
+ s->bucket_tenant = dest_tenant_name;
+ s->bucket_name = dest_bucket_name;
s->object = rgw_obj_key(dest_object);
s->op = OP_PUT;
}
if (ret < 0)
return NULL;
- if (s->bucket_name_str.empty())
+ if (s->bucket_name.empty())
return new RGWHandler_ObjStore_Service_SWIFT;
if (s->object.empty())
return new RGWHandler_ObjStore_Bucket_SWIFT;
int authenticate_temp_url(RGWRados *store, req_state *s)
{
/* temp url requires bucket and object specified in the requets */
- if (s->bucket_name_str.empty())
+ if (s->bucket_name.empty())
return -EPERM;
if (s->object.empty())
/* need to get user info of bucket owner */
RGWBucketInfo bucket_info;
- int ret = store->get_bucket_info(*static_cast<RGWObjectCtx *>(s->obj_ctx), s->bucket_name_str, bucket_info, NULL);
+ int ret = store->get_bucket_info(*static_cast<RGWObjectCtx *>(s->obj_ctx),
+ s->bucket_tenant, s->bucket_name,
+ bucket_info, NULL);
if (ret < 0)
return -EPERM;
s->perm_mask = 0;
map<string, RGWSubUser>::iterator iter = s->user.subusers.find(subuser);
if (iter != s->user.subusers.end()) {
- RGWSubUser& subuser = iter->second;
- s->perm_mask = subuser.perm_mask;
+ RGWSubUser& subuser_ = iter->second;
+ s->perm_mask = subuser_.perm_mask;
}
} else {
s->perm_mask = RGW_PERM_FULL_CONTROL;
RGWUID ui;
ui.user_id = info.user_id;
+ // P3
+ ldout(store->ctx(), 0) << "DEBUG: rgw_store_user_info: user_id " << ui.user_id << dendl;
bufferlist link_bl;
::encode(ui, link_bl);
string key;
info.user_id.to_str(key);
-
+
ret = store->meta_mgr->put_entry(user_meta_handler, key, data_bl, exclusive, &ot, mtime, pattrs);
if (ret < 0)
return ret;
}
int rgw_get_user_attrs_by_uid(RGWRados *store,
- const string& user_id,
+ const rgw_user& user_id,
map<string, bufferlist>& attrs,
RGWObjVersionTracker *objv_tracker)
{
RGWObjectCtx obj_ctx(store);
- rgw_obj obj(store->zone.user_uid_pool, user_id);
+ rgw_obj obj(store->zone.user_uid_pool, user_id.to_str());
RGWRados::SystemObject src(store, obj_ctx, obj);
RGWRados::SystemObject::Read rop(&src);
} else {
set_err_msg(err_msg, "user: " + op_state.user_id.to_str() + " exists");
}
-
return -EEXIST;
}
* Returns: 0 on success, -ERR# on failure.
*/
extern int rgw_get_user_attrs_by_uid(RGWRados *store,
- const string& user_id,
+ const rgw_user& user_id,
map<string, bufferlist>& attrs,
RGWObjVersionTracker *objv_tracker = NULL);
/**
size_t pos = _subuser.find(":");
if (pos != string::npos) {
- user_id = _subuser.substr(0, pos);
+ user_id.id = _subuser.substr(0, pos);
subuser = _subuser.substr(pos+1);
} else {
subuser = _subuser;
RGWUserCaps *get_caps_obj() { return &info.caps; }
std::string build_default_swift_kid() {
- if (user_id.id.empty() || subuser.empty())
+ if (user_id.empty() || subuser.empty())
return "";
- string kid;
+ std::string kid;
user_id.to_str(kid);
kid.append(":");
kid.append(subuser);
}
std::string generate_subuser() {
- if (user_id.id.empty())
+ if (user_id.empty())
return "";
std::string generated_subuser;
#endif
using namespace std;
-static void init_bucket(rgw_bucket *bucket, const char *name)
+static void init_bucket(rgw_bucket *bucket, const char *ten, const char *name)
{
- *bucket = rgw_bucket(name, ".data-pool", ".index-pool", "marker.", "bucket-id", NULL);
+ *bucket = rgw_bucket(ten, name, ".data-pool", ".index-pool", "marker.", "bucket-id", NULL);
}
void append_head(list<rgw_obj> *objs, rgw_obj& head)
{
manifest->set_trivial_rule(head_max_size, stripe_size);
- init_bucket(bucket, "buck");
+ init_bucket(bucket, "", "buck");
*head = rgw_obj(*bucket, "oid");
gen->create_begin(g_ceph_context, manifest, *bucket, *head);
static void init_bucket(rgw_bucket *bucket, const char *name)
{
- *bucket = rgw_bucket(name, ".data-pool", ".index-pool", "marker", "bucket-id", NULL);
+ *bucket = rgw_bucket("", name, ".data-pool", ".index-pool", "marker", "bucket-id", NULL);
}
void check_parsed_correctly(rgw_obj& obj, const string& name, const string& ns, const string& instance)