From 7bbdcdbaabd00a0311d25949eb49773eb0574b87 Mon Sep 17 00:00:00 2001 From: Yehuda Sadeh Date: Fri, 24 Jun 2011 12:55:25 -0700 Subject: [PATCH] rgw: radosgw_admin user rm --purge-data --- src/include/rados/librados.hpp | 2 ++ src/librados.cc | 20 +++++++++++++ src/rgw/rgw_access.h | 1 + src/rgw/rgw_admin.cc | 13 +++++--- src/rgw/rgw_common.h | 6 +++- src/rgw/rgw_op.cc | 4 +-- src/rgw/rgw_rados.cc | 55 ++++++++++++++++++++++++++++++++++ src/rgw/rgw_rados.h | 1 + src/rgw/rgw_user.cc | 49 ++++++++++++++++++++++++------ src/rgw/rgw_user.h | 4 +-- 10 files changed, 137 insertions(+), 18 deletions(-) diff --git a/src/include/rados/librados.hpp b/src/include/rados/librados.hpp index 59ae98fa18caf..77ac98e42da22 100644 --- a/src/include/rados/librados.hpp +++ b/src/include/rados/librados.hpp @@ -288,8 +288,10 @@ namespace librados int pool_create(const char *name, uint64_t auid); int pool_create(const char *name, uint64_t auid, __u8 crush_rule); int pool_delete(const char *name); + int pool_delete_async(const char *name, PoolAsyncCompletion *c); int pool_lookup(const char *name); + int ioctx_create(const char *name, IoCtx &pioctx); /* listing objects */ diff --git a/src/librados.cc b/src/librados.cc index a893dd329ce8d..98aa9116be1ec 100644 --- a/src/librados.cc +++ b/src/librados.cc @@ -521,6 +521,7 @@ public: int pool_change_auid(rados_ioctx_t io, unsigned long long auid); int pool_get_auid(rados_ioctx_t io, unsigned long long *auid); + int pool_delete_async(const char *name, PoolAsyncCompletionImpl *c); int pool_change_auid_async(rados_ioctx_t io, unsigned long long auid, PoolAsyncCompletionImpl *c); int list(Objecter::ListContext *context, int max_entries); @@ -1210,6 +1211,19 @@ pool_delete(const char *name) return reply; } +int librados::RadosClient:: +pool_delete_async(const char *name, PoolAsyncCompletionImpl *c) +{ + int tmp_pool_id = osdmap.lookup_pg_pool_name(name); + if (tmp_pool_id < 0) + return -ENOENT; + + Mutex::Locker l(lock); + objecter->delete_pool(tmp_pool_id, new C_PoolAsync_Safe(c)); + + return 0; +} + /** * Attempt to change a io's associated auid "owner." Requires that you * have write permission on both the current and new auid. @@ -3035,6 +3049,12 @@ pool_delete(const char *name) return client->pool_delete(name); } +int librados::Rados:: +pool_delete_async(const char *name, PoolAsyncCompletion *c) +{ + return client->pool_delete_async(name, c->pc); +} + int librados::Rados:: pool_list(std::list& v) { diff --git a/src/rgw/rgw_access.h b/src/rgw/rgw_access.h index 93a1b0bb85435..1c563e12d292b 100644 --- a/src/rgw/rgw_access.h +++ b/src/rgw/rgw_access.h @@ -100,6 +100,7 @@ public: * Returns 0 on success, -ERR# otherwise. */ virtual int delete_bucket(std::string& id, std::string& bucket) = 0; + virtual int purge_buckets(std::string& id, vector& buckets) { return -ENOTSUP; } virtual int disable_buckets(std::vector& buckets) { return -ENOTSUP; } virtual int enable_buckets(std::vector& buckets, uint64_t auid) { return -ENOTSUP; } diff --git a/src/rgw/rgw_admin.cc b/src/rgw/rgw_admin.cc index b431086aaec9a..bbb17778c1127 100644 --- a/src/rgw/rgw_admin.cc +++ b/src/rgw/rgw_admin.cc @@ -69,6 +69,8 @@ void usage() cerr << " --pool-id=\n"; cerr << " --format= specify output format for certain operations: xml,\n"; cerr << " json\n"; + cerr << " --purge_data when specified, user removal will also purge all the\n"; + cerr << " user data\n"; generic_client_usage(); } @@ -382,6 +384,7 @@ int main(int argc, char **argv) int pool_id = -1; const char *format = 0; RGWFormatter *formatter = &formatter_xml; + bool purge_data = false; FOR_EACH_ARG(args) { if (CEPH_ARGPARSE_EQ("help", 'h')) { @@ -426,6 +429,8 @@ int main(int argc, char **argv) } } else if (CEPH_ARGPARSE_EQ("format", '\0')) { CEPH_ARGPARSE_SET_ARG_VAL(&format, OPT_STR); + } else if (CEPH_ARGPARSE_EQ("purge-data", '\0')) { + CEPH_ARGPARSE_SET_ARG_VAL(&purge_data, OPT_BOOL); } else { if (!opt_cmd) { opt_cmd = get_cmd(CEPH_ARGPARSE_VAL, prev_cmd, &need_more); @@ -483,7 +488,7 @@ int main(int argc, char **argv) user_modify_op = (opt_cmd == OPT_USER_MODIFY || opt_cmd == OPT_SUBUSER_MODIFY || opt_cmd == OPT_SUBUSER_CREATE || opt_cmd == OPT_SUBUSER_RM || - opt_cmd == OPT_KEY_CREATE || opt_cmd == OPT_KEY_RM); + opt_cmd == OPT_KEY_CREATE || opt_cmd == OPT_KEY_RM || opt_cmd == OPT_USER_RM); store = RGWAccess::init_storage_provider("rados", g_ceph_context); if (!store) { @@ -755,7 +760,7 @@ int main(int argc, char **argv) return -EINVAL; } cout << "bucket is linked to user '" << owner.get_id() << "'.. unlinking" << std::endl; - r = rgw_remove_bucket(owner.get_id(), bucket_str); + r = rgw_remove_bucket(owner.get_id(), bucket_str, false); if (r < 0) { cerr << "could not unlink policy from user '" << owner.get_id() << "'" << std::endl; return r; @@ -775,7 +780,7 @@ int main(int argc, char **argv) } string bucket_str(bucket); - int r = rgw_remove_bucket(user_id, bucket_str); + int r = rgw_remove_bucket(user_id, bucket_str, false); if (r < 0) cerr << "error unlinking bucket " << cpp_strerror(-r) << std::endl; return -r; @@ -870,7 +875,7 @@ int main(int argc, char **argv) } if (opt_cmd == OPT_USER_RM) { - rgw_delete_user(info); + rgw_delete_user(info, purge_data); } if (opt_cmd == OPT_POOL_INFO) { diff --git a/src/rgw/rgw_common.h b/src/rgw/rgw_common.h index 5e038e5323de3..59d0f4247f54b 100644 --- a/src/rgw/rgw_common.h +++ b/src/rgw/rgw_common.h @@ -229,7 +229,7 @@ struct RGWUserInfo map subusers; __u8 suspended; - RGWUserInfo() : auid(0) {} + RGWUserInfo() : auid(0), suspended(0) {} void encode(bufferlist& bl) const { __u32 ver = USER_INFO_VER; @@ -598,6 +598,10 @@ public: } }; +inline ostream& operator<<(ostream& out, const rgw_obj o) { + return out << o.bucket << ":" << o.key; +} + static inline void buf_to_hex(const unsigned char *buf, int len, char *str) { int i; diff --git a/src/rgw/rgw_op.cc b/src/rgw/rgw_op.cc index f0ca94a9fd901..5b192a3f403a7 100644 --- a/src/rgw/rgw_op.cc +++ b/src/rgw/rgw_op.cc @@ -421,7 +421,7 @@ void RGWCreateBucket::execute() ret = rgw_add_bucket(s->user.user_id, s->bucket_str); if (ret && !existed && ret != -EEXIST) /* if it exists (or previously existed), don't remove it! */ - rgw_remove_bucket(s->user.user_id, s->bucket_str); + rgw_remove_bucket(s->user.user_id, s->bucket_str, false); if (ret == -EEXIST) ret = 0; @@ -455,7 +455,7 @@ void RGWDeleteBucket::execute() ret = rgwstore->delete_bucket(s->user.user_id, s->bucket_str); if (ret == 0) { - rgw_remove_bucket(s->user.user_id, s->bucket_str); + rgw_remove_bucket(s->user.user_id, s->bucket_str, true); } } diff --git a/src/rgw/rgw_rados.cc b/src/rgw/rgw_rados.cc index 5a971c5f6f9ac..de6b80c494e65 100644 --- a/src/rgw/rgw_rados.cc +++ b/src/rgw/rgw_rados.cc @@ -509,6 +509,61 @@ int RGWRados::delete_bucket(std::string& id, std::string& bucket) return 0; } +/** + * Delete buckets, don't care about content + * id: unused + * bucket: the name of the bucket to delete + * Returns 0 on success, -ERR# otherwise. + */ +int RGWRados::purge_buckets(std::string& id, vector& buckets) +{ + librados::IoCtx list_ctx; + vector::iterator iter; + vector completions; + int ret = 0, r; + + for (iter = buckets.begin(); iter != buckets.end(); ++iter) { + string bucket = *iter; + librados::PoolAsyncCompletion *c = librados::Rados::pool_async_create_completion(); + r = rados->pool_delete_async(bucket.c_str(), c); + if (r < 0) { + RGW_LOG(0) << "WARNING: rados->pool_delete_async(bucket=" << bucket << ") returned err=" << r << dendl; + ret = r; + } else { + completions.push_back(c); + } + + librados::IoCtx io_ctx; + r = rados->ioctx_create(RGW_ROOT_BUCKET, io_ctx); + if (r < 0) { + RGW_LOG(0) << "WARNING: failed to create context in delete_bucket, bucket object leaked" << dendl; + ret = r; + continue; + } + + r = io_ctx.remove(bucket); + if (r < 0) { + RGW_LOG(0) << "WARNING: could not remove bucket object: " << RGW_ROOT_BUCKET << ":" << bucket << dendl; + ret = r; + continue; + } + } + + vector::iterator citer; + for (citer = completions.begin(); citer != completions.end(); ++citer) { + PoolAsyncCompletion *c = *citer; + c->wait(); + r = c->get_return_value(); + if (r < 0) { + RGW_LOG(0) << "WARNING: async pool_removal returned " << r << dendl; + ret = r; + } + c->release(); + } + + return ret; +} + int RGWRados::set_buckets_auid(vector& buckets, uint64_t auid) { librados::IoCtx ctx; diff --git a/src/rgw/rgw_rados.h b/src/rgw/rgw_rados.h index 4ea23367905ba..9e31160e125a7 100644 --- a/src/rgw/rgw_rados.h +++ b/src/rgw/rgw_rados.h @@ -66,6 +66,7 @@ public: struct rgw_err *err); /** delete a bucket*/ virtual int delete_bucket(std::string& id, std::string& bucket); + virtual int purge_buckets(std::string& id, vector& buckets); virtual int disable_buckets(std::vector& buckets); virtual int enable_buckets(std::vector& buckets, uint64_t auid); diff --git a/src/rgw/rgw_user.cc b/src/rgw/rgw_user.cc index 632b04520e671..93e1580e07bdb 100644 --- a/src/rgw/rgw_user.cc +++ b/src/rgw/rgw_user.cc @@ -381,7 +381,7 @@ int rgw_add_bucket(string user_id, string bucket_name) return ret; } -int rgw_remove_bucket(string user_id, string bucket_name) +int rgw_remove_bucket(string user_id, string bucket_name, bool purge_data) { int ret; @@ -408,6 +408,12 @@ int rgw_remove_bucket(string user_id, string bucket_name) } } + if (ret == 0 && purge_data) { + vector buckets; + buckets.push_back(bucket_name); + ret = rgwstore->purge_buckets(user_id, buckets); + } + return ret; } @@ -445,25 +451,50 @@ int rgw_remove_openstack_name_index(string& uid, string& openstack_name) * from the user and user email pools. This leaves the pools * themselves alone, as well as any ACLs embedded in object xattrs. */ -int rgw_delete_user(RGWUserInfo& info) { +int rgw_delete_user(RGWUserInfo& info, bool purge_data) { RGWUserBuckets user_buckets; - rgw_read_user_buckets(info.user_id, user_buckets, false); + int ret = rgw_read_user_buckets(info.user_id, user_buckets, false); + if (ret < 0) + return ret; + map& buckets = user_buckets.get_buckets(); + vector buckets_vec; for (map::iterator i = buckets.begin(); i != buckets.end(); ++i) { string bucket_name = i->first; - rgw_obj obj(rgw_root_bucket, bucket_name); - rgwstore->delete_obj(info.user_id, obj); + buckets_vec.push_back(bucket_name); } map::iterator kiter = info.access_keys.begin(); - for (; kiter != info.access_keys.end(); ++kiter) - rgw_remove_key_index(kiter->second); + for (; kiter != info.access_keys.end(); ++kiter) { + ret = rgw_remove_key_index(kiter->second); + if (ret < 0 && ret != -ENOENT) + RGW_LOG(0) << "ERROR: could not remove " << kiter->first << " (access key object), should be fixed manually (err=" << ret << ")" << dendl; + } rgw_obj uid_obj(ui_uid_bucket, info.user_id); - rgwstore->delete_obj(info.user_id, uid_obj); + ret = rgwstore->delete_obj(info.user_id, uid_obj); + if (ret < 0 && ret != -ENOENT) + RGW_LOG(0) << "ERROR: could not remove " << info.user_id << ":" << uid_obj << ", should be fixed manually (err=" << ret << ")" << dendl; + + string buckets_obj_id; + get_buckets_obj(info.user_id, buckets_obj_id); + rgw_obj uid_bucks(ui_uid_bucket, buckets_obj_id); + ret = rgwstore->delete_obj(info.user_id, uid_bucks); + if (ret < 0 && ret != -ENOENT) + RGW_LOG(0) << "ERROR: could not remove " << info.user_id << ":" << uid_bucks << ", should be fixed manually (err=" << ret << ")" << dendl; + + rgw_obj email_obj(ui_email_bucket, info.user_email); - rgwstore->delete_obj(info.user_id, email_obj); + ret = rgwstore->delete_obj(info.user_id, email_obj); + if (ret < 0 && ret != -ENOENT) + RGW_LOG(0) << "ERROR: could not remove " << info.user_id << ":" << email_obj << ", should be fixed manually (err=" << ret << ")" << dendl; + + if (purge_data) { + ret = rgwstore->purge_buckets(info.user_id, buckets_vec); + if (ret < 0) + RGW_LOG(0) << "ERROR: delete_buckets returned " << ret << dendl; + } return 0; } diff --git a/src/rgw/rgw_user.h b/src/rgw/rgw_user.h index 41d7784d01e1d..99a1648967910 100644 --- a/src/rgw/rgw_user.h +++ b/src/rgw/rgw_user.h @@ -69,7 +69,7 @@ extern int rgw_get_user_info_by_access_key(string& access_key, RGWUserInfo& info /** * Given an RGWUserInfo, deletes the user and its bucket ACLs. */ -extern int rgw_delete_user(RGWUserInfo& user); +extern int rgw_delete_user(RGWUserInfo& user, bool purge_data); /** * Store a list of the user's buckets, with associated functinos. */ @@ -138,7 +138,7 @@ extern int rgw_read_user_buckets(string user_id, RGWUserBuckets& buckets, bool n extern int rgw_write_buckets_attr(string user_id, RGWUserBuckets& buckets); extern int rgw_add_bucket(string user_id, string bucket_name); -extern int rgw_remove_bucket(string user_id, string bucket_name); +extern int rgw_remove_bucket(string user_id, string bucket_name, bool purge_data); /* -- 2.39.5