noinst_LIBRARIES += librgw.a
my_radosgw_ldadd = \
- librgw.a librados.la libcls_rgw_client.a \
- libcls_lock_client.a libcls_refcount_client.a -lcurl -lexpat \
- $(LIBGLOBAL_LDA)
+ libglobal.la librgw.a librados.la libcls_rgw_client.a libcls_log_client.a \
+ libcls_statelog_client.a libcls_replica_log_client.a libcls_lock_client.a \
+ libcls_refcount_client.a libcls_version_client.a -lcurl -lexpat \
- $(PTHREAD_LIBS) -lm $(CRYPTO_LIBS) $(EXTRALIBS)
++ $(PTHREAD_LIBS) -lm $(CRYPTO_LIBS) $(EXTRALIBS) $(LIBGLOBAL_LDA)
radosgw_SOURCES = \
rgw/rgw_resolve.cc \
if WITH_RADOSGW
ceph_test_cors_SOURCES = test/test_cors.cc
- ceph_test_cors_LDFLAGS = libglobal.la
- ceph_test_cors_LDADD = librados.la librgw.a ${UNITTEST_LDADD} ${UNITTEST_STATIC_LDADD} $(CRYPTO_LIBS) -lcurl -luuid -lexpat
+ ceph_test_cors_LDADD = librados.la librgw.a $(LIBGLOBAL_LDA) ${UNITTEST_LDADD} ${UNITTEST_STATIC_LDADD} -lcurl -luuid -lexpat
ceph_test_cors_CXXFLAGS = ${AM_CXXFLAGS} ${UNITTEST_CXXFLAGS}
bin_DEBUGPROGRAMS += ceph_test_cors
+
+cls_test_rgw_meta_SOURCES = test/test_rgw_admin_meta.cc
+cls_test_rgw_meta_LDFLAGS = libglobal.la
+cls_test_rgw_meta_LDADD = librgw.a ${UNITTEST_LDADD} ${UNITTEST_STATIC_LDADD} -lcryptopp -lcurl -luuid -lexpat librados.la libcls_version_client.a \
+ libcls_log_client.a libcls_statelog_client.a libcls_refcount_client.a libcls_rgw_client.a libcls_lock_client.a
+cls_test_rgw_meta_CXXFLAGS = ${AM_CXXFLAGS} ${UNITTEST_CXXFLAGS}
+bin_DEBUGPROGRAMS += cls_test_rgw_meta
+
+cls_test_rgw_log_SOURCES = test/test_rgw_admin_log.cc
+cls_test_rgw_log_LDFLAGS = libglobal.la
+cls_test_rgw_log_LDADD = librgw.a ${UNITTEST_LDADD} ${UNITTEST_STATIC_LDADD} -lcryptopp -lcurl -luuid -lexpat librados.la libcls_version_client.a \
+ libcls_log_client.a libcls_statelog_client.a libcls_refcount_client.a libcls_rgw_client.a libcls_lock_client.a
+cls_test_rgw_log_CXXFLAGS = ${AM_CXXFLAGS} ${UNITTEST_CXXFLAGS}
+bin_DEBUGPROGRAMS += cls_test_rgw_log
+
+cls_test_rgw_opstate_SOURCES = test/test_rgw_admin_opstate.cc
+cls_test_rgw_opstate_LDFLAGS = libglobal.la
+cls_test_rgw_opstate_LDADD = librgw.a ${UNITTEST_LDADD} ${UNITTEST_STATIC_LDADD} -lcryptopp -lcurl -luuid -lexpat librados.la libcls_version_client.a \
+ libcls_log_client.a libcls_statelog_client.a libcls_refcount_client.a libcls_rgw_client.a libcls_lock_client.a
+cls_test_rgw_opstate_CXXFLAGS = ${AM_CXXFLAGS} ${UNITTEST_CXXFLAGS}
+bin_DEBUGPROGRAMS += cls_test_rgw_opstate
endif
ceph_test_librbd_SOURCES = test/librbd/test_librbd.cc test/librados/test.cc
OP_FAILOK = 2,
};
-
+ class ObjectOperationCompletion {
+ public:
+ virtual ~ObjectOperationCompletion() {}
+ virtual void handle_completion(int r, bufferlist& outbl) = 0;
+ };
+
+ /**
+ * These flags apply to the ObjectOperation as a whole.
+ *
+ * BALANCE_READS and LOCALIZE_READS should only be used
+ * when reading from data you're certain won't change,
+ * like a snapshot, or where eventual consistency is ok.
+ */
+ enum ObjectOperationGlobalFlags {
+ OPERATION_NOFLAG = 0,
+ OPERATION_BALANCE_READS = 1,
+ OPERATION_LOCALIZE_READS = 2,
+ };
+
/*
* ObjectOperation : compound object operation
* Batch multiple object operations into a single request, to be applied
map<string, bool> categories;
string caps;
int check_objects = false;
- std::string infile;
RGWUserAdminOpState user_op;
RGWBucketAdminOpState bucket_op;
+ string infile;
+ string metadata_key;
+ RGWObjVersionTracker objv_tracker;
+ string marker;
+ string start_marker;
+ string end_marker;
+ int max_entries = -1;
+ int system = false;
+ bool system_specified = false;
+ int shard_id = -1;
+ bool specified_shard_id = false;
+ string daemon_id;
+ bool specified_daemon_id = false;
+ string client_id;
+ string op_id;
+ string state_str;
+ string replica_log_type_str;
+ ReplicaLogType replica_log_type = ReplicaLog_Invalid;
+ string op_mask_str;
std::string val;
std::ostringstream errs;
pool_name = val;
} else if (ceph_argparse_witharg(args, i, &val, "-o", "--object", (char*)NULL)) {
object = val;
+ } else if (ceph_argparse_witharg(args, i, &val, "--client-id", (char*)NULL)) {
+ client_id = val;
+ } else if (ceph_argparse_witharg(args, i, &val, "--op-id", (char*)NULL)) {
+ op_id = val;
+ } else if (ceph_argparse_witharg(args, i, &val, "--state", (char*)NULL)) {
+ state_str = val;
+ } else if (ceph_argparse_witharg(args, i, &val, "--op-mask", (char*)NULL)) {
+ op_mask_str = val;
} else if (ceph_argparse_witharg(args, i, &val, "--key-type", (char*)NULL)) {
key_type_str = val;
if (key_type_str.compare("swift") == 0) {
}
if (opt_cmd == OPT_GC_LIST) {
- int ret;
int index = 0;
- string marker;
bool truncated;
formatter->open_array_section("entries");
return ret;
obj.bucket = bucket;
- int max = 1000;
- ret = rgw_get_obj(store, NULL, store->zone.domain_root,\
- bucket.name, bl, NULL);
+ ret = rgw_get_system_obj(store, NULL, store->zone.domain_root, bucket.name, bl, NULL, NULL);
bufferlist::iterator iter = bl.begin();
try {
}
if (delete_children) {
- ret = store->list_objects(bucket, max, prefix, delim, marker,\
- objs, common_prefixes,\
- false, ns, (bool *)false, NULL);
+ int max = 1000;
+ ret = store->list_objects(bucket, max, prefix, delim, marker,
+ objs, common_prefixes,
+ false, ns, true, NULL, NULL);
if (ret < 0)
return ret;
private:
public:
- RGWBucket() : store(NULL), failure(false) {}
+ RGWBucket() : store(NULL), handle(NULL), failure(false) {}
int init(RGWRados *storage, RGWBucketAdminOpState& op_state);
- int create_bucket(string bucket_str, string& user_id, string& display_name);
-
int check_bad_index_multipart(RGWBucketAdminOpState& op_state,
list<std::string>& objs_to_unlink, std::string *err_msg = NULL);
if (ret >= 0) {
string& name = nv.get_name();
string& val = nv.get_val();
- val_map[name] = val;
+
+ if (name.compare(0, sizeof(RGW_SYS_PARAM_PREFIX) - 1, RGW_SYS_PARAM_PREFIX) == 0) {
+ sys_val_map[name] = val;
+ } else {
+ val_map[name] = val;
+ }
if ((name.compare("acl") == 0) ||
+ (name.compare("cors") == 0) ||
(name.compare("location") == 0) ||
(name.compare("logging") == 0) ||
(name.compare("delete") == 0) ||
return true;
}
- static struct {
+string rgw_trim_whitespace(const string& src)
+{
+ if (src.empty()) {
+ return string();
+ }
+
+ int start = 0;
+ for (; start != (int)src.size(); start++) {
+ if (!isspace(src[start]))
+ break;
+ }
+
+ int end = src.size() - 1;
+ if (end <= start) {
+ return string();
+ }
+
+ for (; end > start; end--) {
+ if (!isspace(src[end]))
+ break;
+ }
+
+ return src.substr(start, end - start + 1);
+}
+
+string rgw_trim_quotes(const string& val)
+{
+ string s = rgw_trim_whitespace(val);
+ if (s.size() < 2)
+ return s;
+
+ int start = 0;
+ int end = s.size() - 1;
+ int quotes_count = 0;
+
+ if (s[start] == '"') {
+ start++;
+ quotes_count++;
+ }
+ if (s[end] == '"') {
+ end--;
+ quotes_count++;
+ }
+ if (quotes_count == 2) {
+ return s.substr(start, end - start + 1);
+ }
+ return s;
+}
+
+ struct rgw_name_to_flag {
const char *type_name;
- uint32_t perm;
- } cap_names[] = { {"*", RGW_CAP_ALL},
- {"read", RGW_CAP_READ},
- {"write", RGW_CAP_WRITE},
- {NULL, 0} };
+ uint32_t flag;
+ };
- int RGWUserCaps::parse_cap_perm(const string& str, uint32_t *perm)
+ static int parse_list_of_flags(struct rgw_name_to_flag *mapping,
+ const string& str, uint32_t *perm)
{
list<string> strs;
get_str_list(str, strs);
map<string, RGWSubUser> subusers;
__u8 suspended;
uint32_t max_buckets;
+ uint32_t op_mask;
RGWUserCaps caps;
+ __u8 system;
+ string default_placement;
+ list<string> placement_tags;
- RGWUserInfo() : auid(0), suspended(0), max_buckets(RGW_DEFAULT_MAX_BUCKETS), system(0) {}
- RGWUserInfo() : auid(0), suspended(0), max_buckets(RGW_DEFAULT_MAX_BUCKETS), op_mask(RGW_OP_TYPE_ALL) {}
++ RGWUserInfo() : auid(0), suspended(0), max_buckets(RGW_DEFAULT_MAX_BUCKETS), op_mask(RGW_OP_TYPE_ALL), system(0) {}
void encode(bufferlist& bl) const {
- ENCODE_START(12, 9, bl);
+ ENCODE_START(13, 9, bl);
::encode(auid, bl);
string access_key;
string secret_key;
::encode(swift_keys, bl);
::encode(max_buckets, bl);
::encode(caps, bl);
+ ::encode(op_mask, bl);
+ ::encode(system, bl);
+ ::encode(default_placement, bl);
+ ::encode(placement_tags, bl);
ENCODE_FINISH(bl);
}
void decode(bufferlist::iterator& bl) {
-- DECODE_START_LEGACY_COMPAT_LEN_32(11, 9, 9, bl);
++ DECODE_START_LEGACY_COMPAT_LEN_32(13, 9, 9, bl);
if (struct_v >= 2) ::decode(auid, bl);
else auid = CEPH_AUTH_UID_DEFAULT;
string access_key;
if (struct_v >= 11) {
::decode(caps, bl);
}
- system = 0;
if (struct_v >= 12) {
- ::decode(system, bl);
+ ::decode(op_mask, bl);
+ } else {
+ op_mask = RGW_OP_TYPE_ALL;
}
++ system = 0;
+ if (struct_v >= 13) {
++ ::decode(system, bl);
+ ::decode(default_placement, bl);
+ ::decode(placement_tags, bl); /* tags of allowed placement rules */
+ }
DECODE_FINISH(bl);
}
void dump(Formatter *f) const;
encode_json_map("swift_keys", NULL, "key", NULL, user_info_dump_swift_key,(void *)this, swift_keys, f);
encode_json("caps", caps, f);
+
+ char buf[256];
+ op_type_to_str(op_mask, buf, sizeof(buf));
+ encode_json("op_mask", (const char *)buf, f);
++
+ if (system) { /* no need to show it for every user */
+ encode_json("system", (bool)system, f);
+ }
+ encode_json("default_placement", default_placement, f);
+ encode_json("placement_tags", placement_tags, f);
}
JSONDecoder::decode_json("subusers", subusers, decode_subusers, obj);
JSONDecoder::decode_json("caps", caps, obj);
+
+ string mask_str;
+ JSONDecoder::decode_json("op_mask", mask_str, obj);
+ rgw_parse_op_type_list(mask_str, &op_mask);
++
+ bool sys = false;
+ JSONDecoder::decode_json("system", sys, obj);
+ system = (__u8)sys;
+ JSONDecoder::decode_json("default_placement", default_placement, obj);
+ JSONDecoder::decode_json("placement_tags", placement_tags, obj);
}
void rgw_bucket::dump(Formatter *f) const
req->log(s, "reading the cors attr");
handler->read_cors_config();
-
+
+ req->log(s, "verifying op mask");
+ ret = op->verify_op_mask();
+ if (ret < 0) {
+ abort_early(s, ret);
+ goto done;
+ }
+
req->log(s, "verifying op permissions");
ret = op->verify_permission();
if (ret < 0) {
struct req_state;
class RGWHandler;
-void rgw_get_request_metadata(struct req_state *s, map<string, bufferlist>& attrs);
-int rgw_build_policies(RGWRados *store, struct req_state *s, bool only_bucket, bool prefetch_data);
--
/**
* Provide the base class for all ops.
*/
virtual void send_response() = 0;
virtual const char *name() { return "delete_bucket"; }
+ virtual uint32_t op_mask() { return RGW_OP_TYPE_DELETE; }
};
-class RGWPutObjProcessor
-{
-protected:
- RGWRados *store;
- struct req_state *s;
- bool is_complete;
-
- virtual int do_complete(string& etag, map<string, bufferlist>& attrs) = 0;
-
- list<rgw_obj> objs;
-
- void add_obj(rgw_obj& obj) {
- objs.push_back(obj);
- }
-public:
- RGWPutObjProcessor() : store(NULL), s(NULL), is_complete(false) {}
- virtual ~RGWPutObjProcessor();
- virtual int prepare(RGWRados *_store, struct req_state *_s) {
- store = _store;
- s = _s;
- return 0;
- };
- virtual int handle_data(bufferlist& bl, off_t ofs, void **phandle) = 0;
- virtual int throttle_data(void *handle) = 0;
- virtual int complete(string& etag, map<string, bufferlist>& attrs);
-};
-
class RGWPutObj : public RGWOp {
friend class RGWPutObjProcessor;
void *handle = NULL;
- map<string, bufferlist> attrset;
+ map<string, bufferlist> src_attrs;
off_t ofs = 0;
off_t end = -1;
- ret = prepare_get_obj(ctx, src_obj, &ofs, &end, &attrset,
- mod_ptr, unmod_ptr, &lastmod, if_match, if_nomatch, &total_len, &obj_size, &handle, err);
+ if (!remote_src && source_zone.empty()) {
+ ret = prepare_get_obj(ctx, src_obj, &ofs, &end, &src_attrs,
+ mod_ptr, unmod_ptr, &lastmod, if_match, if_nomatch, &total_len, &obj_size, NULL, &handle, err);
+ if (ret < 0)
+ return ret;
+ } else {
+ /* source is in a different region, copy it there */
- if (ret < 0)
- return ret;
+ RGWRESTStreamReadRequest *in_stream_req;
+ string tag;
+ append_rand_alpha(cct, tag, tag, 32);
- if (replace_attrs) {
- if (!attrs[RGW_ATTR_ETAG].length())
- attrs[RGW_ATTR_ETAG] = attrset[RGW_ATTR_ETAG];
+ RGWPutObjProcessor_Atomic processor(dest_obj.bucket, dest_obj.object,
+ cct->_conf->rgw_obj_stripe_size, tag);
+ ret = processor.prepare(this, ctx);
+ if (ret < 0)
+ return ret;
- attrset = attrs;
- } else {
- /* copying attrs from source, however acls should not be copied */
- attrset[RGW_ATTR_ACL] = attrs[RGW_ATTR_ACL];
+ RGWRESTConn *conn;
+ if (source_zone.empty()) {
+ conn = rest_master_conn;
+ } else {
+ map<string, RGWRESTConn *>::iterator iter = zone_conn_map.find(source_zone);
+ if (iter == zone_conn_map.end()) {
+ ldout(cct, 0) << "could not find zone connection to zone: " << source_zone << dendl;
+ return -ENOENT;
+ }
+ conn = iter->second;
+ }
+
+ string obj_name = dest_obj.bucket.name + "/" + dest_obj.object;
+
+ RGWOpStateSingleOp opstate(this, client_id, op_id, obj_name);
+
+ int ret = opstate.set_state(RGWOpState::OPSTATE_IN_PROGRESS);
+ if (ret < 0) {
+ ldout(cct, 0) << "ERROR: failed to set opstate ret=" << ret << dendl;
+ return ret;
+ }
+ RGWRadosPutObj cb(&processor, &opstate);
+ string etag;
+ map<string, string> req_headers;
+ time_t set_mtime;
+
+ ret = conn->get_obj(user_id, info, src_obj, true, &cb, &in_stream_req);
+ if (ret < 0)
+ goto set_err_state;
+
+ ret = conn->complete_request(in_stream_req, etag, &set_mtime, req_headers);
+ if (ret < 0)
+ goto set_err_state;
+
+ { /* opening scope so that we can do goto, sorry */
+ bufferlist& extra_data_bl = processor.get_extra_data();
+ if (extra_data_bl.length()) {
+ JSONParser jp;
+ if (!jp.parse(extra_data_bl.c_str(), extra_data_bl.length())) {
+ ldout(cct, 0) << "failed to parse response extra data. len=" << extra_data_bl.length() << " data=" << extra_data_bl.c_str() << dendl;
+ goto set_err_state;
+ }
+
+ JSONDecoder::decode_json("attrs", src_attrs, &jp);
+
+ src_attrs.erase(RGW_ATTR_MANIFEST); // not interested in original object layout
+ }
+ }
+
+ set_copy_attrs(src_attrs, attrs, replace_attrs, !source_zone.empty());
+
+ ret = cb.complete(etag, mtime, set_mtime, src_attrs);
+ if (ret < 0)
+ goto set_err_state;
+
+ ret = opstate.set_state(RGWOpState::OPSTATE_COMPLETE);
+ if (ret < 0) {
+ ldout(cct, 0) << "ERROR: failed to set opstate ret=" << ret << dendl;
+ }
+
+ return 0;
+set_err_state:
+ int r = opstate.set_state(RGWOpState::OPSTATE_ERROR);
+ if (r < 0) {
+ ldout(cct, 0) << "ERROR: failed to set opstate r=" << ret << dendl;
+ }
+ return ret;
}
-
- attrset.erase(RGW_ATTR_ID_TAG);
+ set_copy_attrs(src_attrs, attrs, replace_attrs, false);
++ src_attrs.erase(RGW_ATTR_ID_TAG);
RGWObjManifest manifest;
RGWObjState *astate = NULL;
r = append_atomic_test(rctx, read_obj, op, &astate);
if (r < 0)
goto done_ret;
- }
- if (objv_tracker) {
- objv_tracker->prepare_op_for_read(&op);
- }
+ if (astate) {
+ if (!ofs && astate->data.length() >= len) {
+ bl = astate->data;
+ goto done;
+ }
- read_len = len;
+ if (ofs < astate->data.length()) {
+ unsigned copy_len = min((uint64_t)astate->data.length() - ofs, len);
+ astate->data.copy(ofs, copy_len, bl);
+ read_len -= copy_len;
+ read_ofs += copy_len;
+ if (!read_len)
+ goto done;
- if (astate) {
- if (!ofs && astate->data.length() >= len) {
- bl = astate->data;
- goto done;
+ merge_bl = true;
+ pbl = &read_bl;
+ }
}
+ }
- if (ofs < astate->data.length()) {
- unsigned copy_len = min((uint64_t)astate->data.length(), len);
- astate->data.copy(ofs, copy_len, bl);
- read_len -= copy_len;
- read_ofs += copy_len;
- if (!read_len)
- goto done;
-
- merge_bl = true;
- pbl = &read_bl;
- }
++ if (objv_tracker) {
++ objv_tracker->prepare_op_for_read(&op);
+ }
+
++
ldout(cct, 20) << "rados->read obj-ofs=" << ofs << " read_ofs=" << read_ofs << " read_len=" << read_len << dendl;
op.read(read_ofs, read_len, pbl, NULL);
for (iter = resources_by_size.rbegin(); iter != resources_by_size.rend(); ++iter) {
string& resource = iter->second;
if (uri.compare(0, iter->first, resource) == 0 &&
- (resource.size() == iter->first ||
- resource[iter->first] == '/')) {
+ (uri.size() == iter->first ||
+ uri[iter->first] == '/')) {
string suffix = uri.substr(iter->first);
- return resource_mgrs[resource]->get_resource_mgr(s, suffix);
+ return resource_mgrs[resource]->get_resource_mgr(s, suffix, out_uri);
}
}
return ret;
}
-int rgw_get_obj(RGWRados *rgwstore, void *ctx, rgw_bucket& bucket, string& key, bufferlist& bl, map<string, bufferlist> *pattrs)
+int rgw_get_system_obj(RGWRados *rgwstore, void *ctx, rgw_bucket& bucket, const string& key, bufferlist& bl,
+ RGWObjVersionTracker *objv_tracker, time_t *pmtime, map<string, bufferlist> *pattrs)
{
- int ret;
struct rgw_err err;
void *handle = NULL;
bufferlist::iterator iter;
int request_len = READ_CHUNK_LEN;
rgw_obj obj(bucket, key);
+
do {
- ret = rgwstore->prepare_get_obj(ctx, obj, NULL, NULL, pattrs, NULL,
- NULL, pmtime, NULL, NULL, NULL, NULL, objv_tracker, &handle, &err);
+ int ret = rgwstore->prepare_get_obj(ctx, obj, NULL, NULL, pattrs, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, &handle, &err);
++ NULL, pmtime, NULL, NULL, NULL, NULL,
++ objv_tracker, &handle, &err);
if (ret < 0)
return ret;
user_info.max_buckets = op_state.get_max_buckets();
user_info.suspended = op_state.get_suspension_status();
+ user_info.system = op_state.system;
+ if (op_state.op_mask_specified)
+ user_info.op_mask = op_state.get_op_mask();
+
// update the request
op_state.set_user_info(user_info);
op_state.set_populated();
if (op_state.max_buckets_specified)
user_info.max_buckets = max_buckets;
+ if (op_state.system_specified)
+ user_info.system = op_state.system;
+
+ if (op_state.op_mask_specified)
+ user_info.op_mask = op_state.get_op_mask();
+
if (op_state.has_suspension_op()) {
__u8 suspended = op_state.get_suspension_status();
user_info.suspended = suspended;
std::string display_name;
uint32_t max_buckets;
__u8 suspended;
+ __u8 system;
std::string caps;
+ RGWObjVersionTracker objv;
+ uint32_t op_mask;
// subuser attributes
std::string subuser;
bool user_email_specified;
bool max_buckets_specified;
bool perm_specified;
+ bool op_mask_specified;
bool caps_specified;
bool suspension_op;
+ bool system_specified;
bool key_op;
// req parameters
key_type = -1;
perm_mask = 0;
suspended = 0;
+ system = 0;
+ op_mask = 0;
existing_user = false;
existing_key = false;