summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSage Weil <sage@inktank.com>2012-07-11 18:56:00 -0700
committerSage Weil <sage@inktank.com>2012-07-11 18:56:00 -0700
commitf20b602296066a6a094409cbb0d92183adcd2717 (patch)
tree9ac1480823fe25bd5845b2ae1bc7a294ff762f79
parent0782db3694e10db0cdeb678d5771f378e1a372ca (diff)
parent99a048d882fb6f809e78cca92d9c8888ac093c82 (diff)
downloadceph-f20b602296066a6a094409cbb0d92183adcd2717.tar.gz
Merge branch 'next'
Conflicts: src/rados.cc
-rw-r--r--ceph.spec.in2
-rw-r--r--debian/librados-dev.install2
-rw-r--r--src/Makefile.am12
-rw-r--r--src/common/armor.c4
-rw-r--r--src/rados.cc216
-rw-r--r--src/rgw/rgw_admin.cc35
-rw-r--r--src/rgw/rgw_common.cc47
-rw-r--r--src/rgw/rgw_common.h20
-rw-r--r--src/rgw/rgw_rados.cc6
-rw-r--r--src/rgw/rgw_rest_s3.cc23
-rwxr-xr-xsrc/test/test_rados_tool.sh76
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