diff options
author | Sage Weil <sage@inktank.com> | 2012-07-11 18:56:00 -0700 |
---|---|---|
committer | Sage Weil <sage@inktank.com> | 2012-07-11 18:56:00 -0700 |
commit | f20b602296066a6a094409cbb0d92183adcd2717 (patch) | |
tree | 9ac1480823fe25bd5845b2ae1bc7a294ff762f79 | |
parent | 0782db3694e10db0cdeb678d5771f378e1a372ca (diff) | |
parent | 99a048d882fb6f809e78cca92d9c8888ac093c82 (diff) | |
download | ceph-f20b602296066a6a094409cbb0d92183adcd2717.tar.gz |
Merge branch 'next'
Conflicts:
src/rados.cc
-rw-r--r-- | ceph.spec.in | 2 | ||||
-rw-r--r-- | debian/librados-dev.install | 2 | ||||
-rw-r--r-- | src/Makefile.am | 12 | ||||
-rw-r--r-- | src/common/armor.c | 4 | ||||
-rw-r--r-- | src/rados.cc | 216 | ||||
-rw-r--r-- | src/rgw/rgw_admin.cc | 35 | ||||
-rw-r--r-- | src/rgw/rgw_common.cc | 47 | ||||
-rw-r--r-- | src/rgw/rgw_common.h | 20 | ||||
-rw-r--r-- | src/rgw/rgw_rados.cc | 6 | ||||
-rw-r--r-- | src/rgw/rgw_rest_s3.cc | 23 | ||||
-rwxr-xr-x | src/test/test_rados_tool.sh | 76 |
11 files changed, 371 insertions, 72 deletions
diff --git a/ceph.spec.in b/ceph.spec.in index c69f3c45d11..70e9e08912c 100644 --- a/ceph.spec.in +++ b/ceph.spec.in @@ -326,6 +326,8 @@ fi /usr/sbin/rcceph %{_libdir}/rados-classes/libcls_rbd.so* %{_libdir}/rados-classes/libcls_rgw.so* +/sbin/ceph-disk-activate +/sbin/ceph-disk-prepare ################################################################################# %files fuse diff --git a/debian/librados-dev.install b/debian/librados-dev.install index b92d5e28519..ecc29c7cf36 100644 --- a/debian/librados-dev.install +++ b/debian/librados-dev.install @@ -6,3 +6,5 @@ usr/include/rados/librados.hpp usr/include/rados/buffer.h usr/include/rados/page.h usr/include/rados/crc32c.h +usr/bin/librados-config +usr/share/man/man8/librados-config.8 diff --git a/src/Makefile.am b/src/Makefile.am index 8702f3cc6d4..82c33f3f245 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -950,12 +950,12 @@ rados_include_DATA = \ $(srcdir)/include/page.h \ $(srcdir)/include/crc32c.h -crush_includedir = $(includedir)/crush -crush_include_DATA = \ - $(srcdir)/crush/hash.h \ - $(srcdir)/crush/crush.h \ - $(srcdir)/crush/mapper.h \ - $(srcdir)/crush/types.h +#crush_includedir = $(includedir)/crush +#crush_include_DATA = \ +# $(srcdir)/crush/hash.h \ +# $(srcdir)/crush/crush.h \ +# $(srcdir)/crush/mapper.h \ +# $(srcdir)/crush/types.h FORCE: .git_version: FORCE diff --git a/src/common/armor.c b/src/common/armor.c index d1d56649532..e4b8b86928e 100644 --- a/src/common/armor.c +++ b/src/common/armor.c @@ -24,9 +24,9 @@ static int decode_bits(char c) return c - 'a' + 26; if (c >= '0' && c <= '9') return c - '0' + 52; - if (c == '+') + if (c == '+' || c == '-') return 62; - if (c == '/') + if (c == '/' || c == '_') return 63; if (c == '=') return 0; /* just non-negative, please */ diff --git a/src/rados.cc b/src/rados.cc index 95bfbdbe1ab..e5bdddd0ad0 100644 --- a/src/rados.cc +++ b/src/rados.cc @@ -55,13 +55,13 @@ void usage(ostream& out) out << \ "usage: rados [options] [commands]\n" "POOL COMMANDS\n" -" lspools list pools\n" +" lspools list pools\n" " mkpool <pool-name> [123[ 4]] create pool <pool-name>'\n" " [with auid 123[and using crush rule 4]]\n" +" cppool <pool-name> <dest-pool> copy content of a pool\n" " rmpool <pool-name> remove pool <pool-name>'\n" -" mkpool <pool-name> create the pool <pool-name>\n" -" df show per-pool and total usage\n" -" ls list objects in pool\n" +" df show per-pool and total usage\n" +" ls list objects in pool\n\n" " chown 123 change the pool owner to auid 123\n" "\n" "OBJECT COMMANDS\n" @@ -69,6 +69,7 @@ void usage(ostream& out) " put <obj-name> [infile] write object\n" " create <obj-name> [category] create object\n" " rm <obj-name> remove object\n" +" cp <obj-name> [target-obj] copy object\n" " listxattr <obj-name>\n" " getxattr <obj-name> attr\n" " setxattr <obj-name> attr val\n" @@ -85,7 +86,7 @@ void usage(ostream& out) " load-gen [options] generate load on the cluster\n" " listomapkeys <obj-name> list the keys in the object map\n" " getomapval <obj-name> <key> show the value for the specified key\n" - "in the object's object map\n" +" in the object's object map\n" " setomapval <obj-name> <key> <val>\n" " listomapvals <obj-name> <key> <val>\n" " rmomapkey <obj-name> <key> <val>\n" @@ -103,7 +104,7 @@ void usage(ostream& out) " files or objects from the target bucket\n" " or directory.\n" " --workers Number of worker threads to spawn \n" -" default " STR(DEFAULT_NUM_RADOS_WORKER_THREADS) "\n" +" (default " STR(DEFAULT_NUM_RADOS_WORKER_THREADS) ")\n" "\n" "GLOBAL OPTIONS:\n" " --object_locator object_locator\n" @@ -111,6 +112,8 @@ void usage(ostream& out) " -p pool\n" " --pool=pool\n" " select given pool by name\n" +" --target-pool=pool\n" +" select target pool by name\n" " -b op_size\n" " set the size of write ops for put or benchmarking\n" " -s name\n" @@ -167,6 +170,133 @@ static int do_get(IoCtx& io_ctx, const char *objname, const char *outfile, bool return 0; } +static int do_copy(IoCtx& io_ctx, const char *objname, IoCtx& target_ctx, const char *target_obj) +{ + string oid(objname); + bufferlist outdata; + librados::ObjectReadOperation read_op; + string start_after; + +#define COPY_CHUNK_SIZE (4 * 1024 * 1024) + read_op.read(0, COPY_CHUNK_SIZE, &outdata, NULL); + + map<std::string, bufferlist> attrset; + read_op.getxattrs(&attrset, NULL); + + bufferlist omap_header; + read_op.omap_get_header(&omap_header, NULL); + +#define OMAP_CHUNK 1000 + map<string, bufferlist> omap; + read_op.omap_get_vals(start_after, OMAP_CHUNK, &omap, NULL); + + bufferlist opbl; + int ret = io_ctx.operate(oid, &read_op, &opbl); + if (ret < 0) { + return ret; + } + + librados::ObjectWriteOperation write_op; + string target_oid(target_obj); + + /* reset dest if exists */ + write_op.create(false); + write_op.remove(); + + write_op.write_full(outdata); + write_op.omap_set_header(omap_header); + + map<std::string, bufferlist>::iterator iter; + for (iter = attrset.begin(); iter != attrset.end(); ++iter) { + write_op.setxattr(iter->first.c_str(), iter->second); + } + if (omap.size()) { + write_op.omap_set(omap); + } + ret = target_ctx.operate(target_oid, &write_op); + if (ret < 0) { + return ret; + } + + uint64_t off = 0; + + while (outdata.length() == COPY_CHUNK_SIZE) { + off += outdata.length(); + outdata.clear(); + ret = io_ctx.read(oid, outdata, COPY_CHUNK_SIZE, off); + if (ret < 0) + goto err; + + ret = target_ctx.write(target_oid, outdata, outdata.length(), off); + if (ret < 0) + goto err; + } + + /* iterate through source omap and update target. This is not atomic */ + while (omap.size() == OMAP_CHUNK) { + /* now start_after should point at the last entry */ + map<string, bufferlist>::iterator iter = omap.end(); + --iter; + start_after = iter->first; + + omap.clear(); + ret = io_ctx.omap_get_vals(oid, start_after, OMAP_CHUNK, &omap); + if (ret < 0) + goto err; + + if (!omap.size()) + break; + + ret = target_ctx.omap_set(target_oid, omap); + if (ret < 0) + goto err; + } + + return 0; + +err: + target_ctx.remove(target_oid); + return ret; +} + +static int do_copy_pool(Rados& rados, const char *src_pool, const char *target_pool) +{ + IoCtx src_ctx, target_ctx; + int ret = rados.ioctx_create(src_pool, src_ctx); + if (ret < 0) { + cerr << "cannot open source pool: " << src_pool << std::endl; + return ret; + } + ret = rados.ioctx_create(target_pool, target_ctx); + if (ret < 0) { + cerr << "cannot open target pool: " << target_pool << std::endl; + return ret; + } + librados::ObjectIterator i = src_ctx.objects_begin(); + librados::ObjectIterator i_end = src_ctx.objects_end(); + for (; i != i_end; ++i) { + string oid = i->first; + string locator = i->second; + if (i->second.size()) + cout << src_pool << ":" << oid << "(@" << locator << ")" << " => " + << target_pool << ":" << oid << "(@" << locator << ")" << std::endl; + else + cout << src_pool << ":" << oid << " => " + << target_pool << ":" << oid << std::endl; + + + target_ctx.locator_set_key(locator); + ret = do_copy(src_ctx, oid.c_str(), target_ctx, oid.c_str()); + if (ret < 0) { + char buf[64]; + cerr << "error copying object: " << strerror_r(errno, buf, sizeof(buf)) << std::endl; + return ret; + } + } + + return 0; +} + static int do_put(IoCtx& io_ctx, const char *objname, const char *infile, int op_size, bool check_stdio) { string oid(objname); @@ -665,7 +795,8 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts, int ret; bool create_pool = false; const char *pool_name = NULL; - string oloc; + const char *target_pool_name = NULL; + string oloc, target_oloc; int concurrent_ios = 16; int op_size = 1 << 22; const char *snapname = NULL; @@ -697,10 +828,18 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts, if (i != opts.end()) { pool_name = i->second.c_str(); } + i = opts.find("target_pool"); + if (i != opts.end()) { + target_pool_name = i->second.c_str(); + } i = opts.find("object_locator"); if (i != opts.end()) { oloc = i->second; } + i = opts.find("target_locator"); + if (i != opts.end()) { + target_oloc = i->second; + } i = opts.find("category"); if (i != opts.end()) { category = i->second; @@ -1241,6 +1380,46 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts, } while (ret == MAX_READ); ret = 0; } + else if (strcmp(nargs[0], "cp") == 0) { + if (!pool_name) + usage_exit(); + + if (nargs.size() < 2 || nargs.size() > 3) + usage_exit(); + + const char *target = target_pool_name; + if (!target) + target = pool_name; + + const char *target_obj; + if (nargs.size() < 3) { + if (strcmp(target, pool_name) == 0) { + cerr << "cannot copy object into itself" << std::endl; + return 1; + } + target_obj = nargs[1]; + } else { + target_obj = nargs[2]; + } + + // open io context. + IoCtx target_ctx; + ret = rados.ioctx_create(target, target_ctx); + if (ret < 0) { + cerr << "error opening target pool " << target << ": " + << strerror_r(-ret, buf, sizeof(buf)) << std::endl; + return 1; + } + if (target_oloc.size()) { + target_ctx.locator_set_key(target_oloc); + } + + ret = do_copy(io_ctx, nargs[1], target_ctx, target_obj); + if (ret < 0) { + cerr << "error copying " << pool_name << "/" << nargs[1] << " => " << target << "/" << target_obj << ": " << strerror_r(-ret, buf, sizeof(buf)) << std::endl; + return 1; + } + } else if (strcmp(nargs[0], "rm") == 0) { if (!pool_name || nargs.size() < 2) usage_exit(); @@ -1330,6 +1509,25 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts, } cout << "successfully created pool " << nargs[1] << std::endl; } + else if (strcmp(nargs[0], "cppool") == 0) { + if (nargs.size() != 3) + usage_exit(); + const char *src_pool = nargs[1]; + const char *target_pool = nargs[2]; + + if (strcmp(src_pool, target_pool) == 0) { + cerr << "cannot copy pool into itself" << std::endl; + return 1; + } + + ret = do_copy_pool(rados, src_pool, target_pool); + if (ret < 0) { + cerr << "error copying pool " << src_pool << " => " << target_pool << ": " + << strerror_r(-ret, buf, sizeof(buf)) << std::endl; + return 1; + } + cout << "successfully copied pool " << nargs[1] << std::endl; + } else if (strcmp(nargs[0], "rmpool") == 0) { if (nargs.size() < 2) usage_exit(); @@ -1552,8 +1750,12 @@ int main(int argc, const char **argv) opts["show-time"] = "true"; } else if (ceph_argparse_witharg(args, i, &val, "-p", "--pool", (char*)NULL)) { opts["pool"] = val; + } else if (ceph_argparse_witharg(args, i, &val, "--target-pool", (char*)NULL)) { + opts["target_pool"] = val; } else if (ceph_argparse_witharg(args, i, &val, "--object-locator" , (char *)NULL)) { opts["object_locator"] = val; + } else if (ceph_argparse_witharg(args, i, &val, "--target-locator" , (char *)NULL)) { + opts["target_locator"] = val; } else if (ceph_argparse_witharg(args, i, &val, "--category", (char*)NULL)) { opts["category"] = val; } else if (ceph_argparse_witharg(args, i, &val, "-t", "--concurrent-ios", (char*)NULL)) { diff --git a/src/rgw/rgw_admin.cc b/src/rgw/rgw_admin.cc index 8d44c10cfce..244ce486a69 100644 --- a/src/rgw/rgw_admin.cc +++ b/src/rgw/rgw_admin.cc @@ -863,30 +863,15 @@ int main(int argc, char **argv) map<string, RGWSubUser>::iterator uiter; RGWUserInfo old_info = info; - if ((!bucket_name.empty()) || !bucket_id.empty()) { - if (!bucket_id.empty()) { - int ret = rgwstore->get_bucket_info(NULL, bucket_id, bucket_info); - - if (ret < 0) { - cerr << "could not retrieve bucket info for bucket_id=" << bucket_id << std::endl; - return ret; - } - bucket = bucket_info.bucket; - if ((!bucket_name.empty()) && bucket.name.compare(bucket_name.c_str()) != 0) { - cerr << "bucket name does not match bucket id (expected bucket name: " << bucket.name << ")" << std::endl; - return -EINVAL; - } - } else { - string bucket_name_str = bucket_name; - RGWBucketInfo bucket_info; - int r = rgwstore->get_bucket_info(NULL, bucket_name_str, bucket_info); - if (r < 0) { - cerr << "could not get bucket info for bucket=" << bucket_name_str << std::endl; - return r; - } - bucket = bucket_info.bucket; - bucket_id = bucket.bucket_id; + if (!bucket_name.empty()) { + string bucket_name_str = bucket_name; + RGWBucketInfo bucket_info; + int r = rgwstore->get_bucket_info(NULL, bucket_name_str, bucket_info); + if (r < 0) { + cerr << "could not get bucket info for bucket=" << bucket_name_str << std::endl; + return r; } + bucket = bucket_info.bucket; } int err; @@ -1325,8 +1310,8 @@ next: } if (opt_cmd == OPT_BUCKET_STATS) { - if (bucket_name.empty() && bucket_id.empty() && user_id.empty()) { - cerr << "either bucket or bucket-id or uid needs to be specified" << std::endl; + if (bucket_name.empty() && user_id.empty()) { + cerr << "either bucket or uid needs to be specified" << std::endl; return usage(); } formatter->reset(); diff --git a/src/rgw/rgw_common.cc b/src/rgw/rgw_common.cc index 3ff0792b5d2..9aeb24a1a04 100644 --- a/src/rgw/rgw_common.cc +++ b/src/rgw/rgw_common.cc @@ -294,16 +294,28 @@ int XMLArgs::parse() NameVal nv(nameval); int ret = nv.parse(); if (ret >= 0) { - val_map[nv.get_name()] = nv.get_val(); - - if ((nv.get_name().compare("acl") == 0) || - (nv.get_name().compare("location") == 0) || - (nv.get_name().compare("uploads") == 0) || - (nv.get_name().compare("partNumber") == 0) || - (nv.get_name().compare("uploadId") == 0) || - (nv.get_name().compare("versionid") == 0) || - (nv.get_name().compare("torrent") == 0)) { - sub_resources[nv.get_name()] = nv.get_val(); + string& name = nv.get_name(); + string& val = nv.get_val(); + val_map[name] = val; + + if ((name.compare("acl") == 0) || + (name.compare("location") == 0) || + (name.compare("uploads") == 0) || + (name.compare("partNumber") == 0) || + (name.compare("uploadId") == 0) || + (name.compare("versionId") == 0) || + (name.compare("torrent") == 0)) { + sub_resources[name] = val; + } else if (name[0] == 'r') { // root of all evil + if ((name.compare("response-content-type") == 0) || + (name.compare("response-content-language") == 0) || + (name.compare("response-expires") == 0) || + (name.compare("response-cache-control") == 0) || + (name.compare("response-content-disposition") == 0) || + (name.compare("response-content-encoding") == 0)) { + sub_resources[name] = val; + has_resp_modifier = true; + } } } @@ -313,19 +325,22 @@ int XMLArgs::parse() return 0; } -string& XMLArgs::get(string& name) +string& XMLArgs::get(string& name, bool *exists) { map<string, string>::iterator iter; iter = val_map.find(name); - if (iter == val_map.end()) - return empty_str; - return iter->second; + bool e = (iter != val_map.end()); + if (exists) + *exists = e; + if (e) + return iter->second; + return empty_str; } -string& XMLArgs::get(const char *name) +string& XMLArgs::get(const char *name, bool *exists) { string s(name); - return get(s); + return get(s, exists); } bool verify_bucket_permission(struct req_state *s, int perm) diff --git a/src/rgw/rgw_common.h b/src/rgw/rgw_common.h index aa525718e86..22f69f45ac7 100644 --- a/src/rgw/rgw_common.h +++ b/src/rgw/rgw_common.h @@ -210,16 +210,22 @@ class XMLArgs string str, empty_str; map<string, string> val_map; map<string, string> sub_resources; + + bool has_resp_modifier; public: - XMLArgs() {} - XMLArgs(string s) : str(s) {} + XMLArgs() : has_resp_modifier(false) {} /** Set the arguments; as received */ - void set(string s) { val_map.clear(); sub_resources.clear(); str = s; } + void set(string s) { + has_resp_modifier = false; + val_map.clear(); + sub_resources.clear(); + str = s; + } /** parse the received arguments */ int parse(); /** Get the value for a specific argument parameter */ - string& get(string& name); - string& get(const char *name); + string& get(string& name, bool *exists = NULL); + string& get(const char *name, bool *exists = NULL); /** see if a parameter is contained in this XMLArgs */ bool exists(const char *name) { map<string, string>::iterator iter = val_map.find(name); @@ -230,6 +236,10 @@ class XMLArgs return (iter != sub_resources.end()); } map<string, string>& get_sub_resources() { return sub_resources; } + + bool has_response_modifier() { + return has_resp_modifier; + } }; class RGWConf; diff --git a/src/rgw/rgw_rados.cc b/src/rgw/rgw_rados.cc index e7032a0dd97..e4056c569ab 100644 --- a/src/rgw/rgw_rados.cc +++ b/src/rgw/rgw_rados.cc @@ -647,12 +647,6 @@ int RGWRados::store_bucket_info(RGWBucketInfo& info, map<string, bufferlist> *pa if (ret < 0) return ret; - ret = rgw_put_obj(info.owner, pi_buckets_rados, info.bucket.bucket_id, bl.c_str(), bl.length(), false, pattrs); - if (ret < 0) { - ldout(cct, 0) << "ERROR: failed to store " << pi_buckets_rados << ":" << info.bucket.bucket_id << " ret=" << ret << dendl; - return ret; - } - ldout(cct, 20) << "store_bucket_info: bucket=" << info.bucket << " owner " << info.owner << dendl; return 0; } diff --git a/src/rgw/rgw_rest_s3.cc b/src/rgw/rgw_rest_s3.cc index b6f0fa11c55..968b329d2ef 100644 --- a/src/rgw/rgw_rest_s3.cc +++ b/src/rgw/rgw_rest_s3.cc @@ -41,6 +41,7 @@ void dump_bucket(struct req_state *s, RGWBucketEnt& obj) int RGWGetObj_REST_S3::send_response(bufferlist& bl) { + string content_type_str; const char *content_type = NULL; int orig_ret = ret; @@ -66,6 +67,28 @@ int RGWGetObj_REST_S3::send_response(bufferlist& bl) } } + if (s->args.has_response_modifier()) { + bool exists; + content_type_str = s->args.get("response-content-type", &exists); + if (exists) + content_type = content_type_str.c_str(); + string val = s->args.get("response-content-language", &exists); + if (exists) + CGI_PRINTF(s, "Content-Language: %s\n", val.c_str()); + val = s->args.get("response-expires", &exists); + if (exists) + CGI_PRINTF(s, "Expires: %s\n", val.c_str()); + val = s->args.get("response-cache-control", &exists); + if (exists) + CGI_PRINTF(s, "Cache-Control: %s\n", val.c_str()); + val = s->args.get("response-content-disposition", &exists); + if (exists) + CGI_PRINTF(s, "Content-Disposition: %s\n", val.c_str()); + val = s->args.get("response-content-encoding", &exists); + if (exists) + CGI_PRINTF(s, "Content-Encoding: %s\n", val.c_str()); + } + for (iter = attrs.begin(); iter != attrs.end(); ++iter) { const char *name = iter->first.c_str(); if (strncmp(name, RGW_ATTR_META_PREFIX, sizeof(RGW_ATTR_META_PREFIX)-1) == 0) { diff --git a/src/test/test_rados_tool.sh b/src/test/test_rados_tool.sh index d97a71df16a..c454d9f931f 100755 --- a/src/test/test_rados_tool.sh +++ b/src/test/test_rados_tool.sh @@ -15,21 +15,32 @@ test_rados_tool.sh: tests rados_tool EOF } +do_run() { + if [ "$1" == "--tee" ]; then + shift + tee_out="$1" + shift + "$@" | tee $tee_out + else + "$@" + fi +} + run_expect_fail() { - echo "RUN_EXPECT_FAIL: " $@ - $@ + echo "RUN_EXPECT_FAIL: " "$@" + do_run "$@" [ $? -eq 0 ] && die "expected failure, but got success! cmd: $@" } run_expect_succ() { - echo "RUN_EXPECT_SUCC: " $@ - $@ + echo "RUN_EXPECT_SUCC: " "$@" + do_run "$@" [ $? -ne 0 ] && die "expected success, but got failure! cmd: $@" } run() { echo "RUN: " $@ - $@ + do_run "$@" } DNAME="`dirname $0`" @@ -37,6 +48,8 @@ DNAME="`readlink -f $DNAME`" RADOS_TOOL="`readlink -f \"$DNAME/../rados\"`" KEEP_TEMP_FILES=0 POOL=trs_pool +POOL_CP_TARGET=trs_pool.2 + [ -x "$RADOS_TOOL" ] || die "couldn't find $RADOS_TOOL binary to test" [ -x "$RADOS_TOOL" ] || die "couldn't find $RADOS_TOOL binary" which attr &>/dev/null @@ -154,5 +167,58 @@ touch "$TDIR/dire/tmp\$tmp" run_expect_succ "$RADOS_TOOL" --delete-after --create export "$POOL" "$TDIR/dire" | tee "$TDIR/out7" run_expect_succ grep temporary "$TDIR/out7" + +# test copy pool +run "$RADOS_TOOL" rmpool "$POOL" +run "$RADOS_TOOL" rmpool "$POOL_CP_TARGET" +run_expect_succ "$RADOS_TOOL" mkpool "$POOL" +run_expect_succ "$RADOS_TOOL" mkpool "$POOL_CP_TARGET" + +# create src files +mkdir -p "$TDIR/dir_cp_src" +for i in `seq 1 5`; do + fname="$TDIR/dir_cp_src/f.$i" + objname="f.$i" + dd if=/dev/urandom of="$fname" bs=$((1024*1024)) count=$i + run_expect_succ "$RADOS_TOOL" -p "$POOL" put $objname "$fname" + +# a few random attrs + for j in `seq 1 4`; do + rand_str=`dd if=/dev/urandom bs=4 count=1 | hexdump -x` + run_expect_succ "$RADOS_TOOL" -p "$POOL" setxattr $objname attr.$j "$rand_str" + run_expect_succ --tee "$fname.attr.$j" "$RADOS_TOOL" -p "$POOL" getxattr $objname attr.$j + done + + rand_str=`dd if=/dev/urandom bs=4 count=1 | hexdump -x` + run_expect_succ "$RADOS_TOOL" -p "$POOL" setomapheader $objname "$rand_str" + run_expect_succ --tee "$fname.omap.header" "$RADOS_TOOL" -p "$POOL" getomapheader $objname +# a few random omap keys + for j in `seq 1 4`; do + rand_str=`dd if=/dev/urandom bs=4 count=1 | hexdump -x` + run_expect_succ "$RADOS_TOOL" -p "$POOL" setomapval $objname key.$j "$rand_str" + done + run_expect_succ --tee "$fname.omap.vals" "$RADOS_TOOL" -p "$POOL" listomapvals $objname +done + +run_expect_succ "$RADOS_TOOL" cppool "$POOL" "$POOL_CP_TARGET" + +mkdir -p "$TDIR/dir_cp_dst" +for i in `seq 1 5`; do + fname="$TDIR/dir_cp_dst/f.$i" + objname="f.$i" + run_expect_succ "$RADOS_TOOL" -p "$POOL_CP_TARGET" get $objname "$fname" + +# a few random attrs + for j in `seq 1 4`; do + run_expect_succ --tee "$fname.attr.$j" "$RADOS_TOOL" -p "$POOL_CP_TARGET" getxattr $objname attr.$j + done + + run_expect_succ --tee "$fname.omap.header" "$RADOS_TOOL" -p "$POOL_CP_TARGET" getomapheader $objname + run_expect_succ --tee "$fname.omap.vals" "$RADOS_TOOL" -p "$POOL_CP_TARGET" listomapvals $objname +done + +diff -q -r "$TDIR/dir_cp_src" "$TDIR/dir_cp_dst" \ + || die "copy pool validation failed!" + echo "SUCCESS!" exit 0 |