#include #include #include #include using namespace std; #include "common/config.h" #include "common/ceph_argparse.h" #include "common/Formatter.h" #include "global/global_init.h" #include "common/errno.h" #include "common/armor.h" #include "rgw_user.h" #include "rgw_access.h" #include "rgw_acl.h" #include "rgw_acl_s3.h" #include "rgw_log.h" #include "rgw_formats.h" #include "auth/Crypto.h" #define DOUT_SUBSYS rgw #define SECRET_KEY_LEN 40 #define PUBLIC_ID_LEN 20 void _usage() { cerr << "usage: radosgw-admin [options...]" << std::endl; cerr << "commands:\n"; cerr << " user create create a new user\n" ; cerr << " user modify modify user\n"; cerr << " user info get user info\n"; cerr << " user rm remove user\n"; cerr << " user suspend suspend a user\n"; cerr << " user enable reenable user after suspension\n"; cerr << " subuser create create a new subuser\n" ; cerr << " subuser modify modify subuser\n"; cerr << " subuser rm remove subuser\n"; cerr << " key create create access key\n"; cerr << " key rm remove access key\n"; cerr << " bucket list list buckets\n"; cerr << " bucket link link bucket to specified user\n"; cerr << " bucket unlink unlink bucket from specified user\n"; cerr << " bucket stats returns bucket statistics\n"; cerr << " bucket info show bucket information\n"; cerr << " pool add add an existing pool for data placement\n"; cerr << " pool rm remove an existing pool from data placement set\n"; cerr << " pools list list placement active set\n"; cerr << " policy read bucket/object policy\n"; cerr << " log list list log objects\n"; cerr << " log show dump a log from specific object or (bucket + date\n"; cerr << " + bucket-id)\n"; cerr << " log rm remove log object\n"; cerr << " temp remove remove temporary objects that were created up to\n"; cerr << " specified date (and optional time)\n"; cerr << "options:\n"; cerr << " --uid= user id\n"; cerr << " --auth-uid= librados uid\n"; cerr << " --subuser= subuser name\n"; cerr << " --access-key= S3 access key\n"; cerr << " --email=\n"; cerr << " --secret= specify secret key\n"; cerr << " --gen-access-key generate random access key (for S3)\n"; cerr << " --gen-secret generate random secret key\n"; cerr << " --key-type= key type, options are: swift, s3\n"; cerr << " --access= Set access permissions for sub-user, should be one\n"; cerr << " of read, write, readwrite, full\n"; cerr << " --display-name=\n"; cerr << " --bucket=\n"; cerr << " --pool=\n"; cerr << " --object=\n"; cerr << " --date=\n"; cerr << " --time=\n"; cerr << " --bucket-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"; cerr << " --purge-keys when specified, subuser removal will also purge all the\n"; cerr << " subuser keys\n"; cerr << " --show-log-entries= enable/disable dump of log entries on log show\n"; cerr << " --show-log-sum= enable/disable dump of log summation on log show\n"; cerr << " --skip-zero-entries log show only dumps entries that don't have zero value\n"; cerr << " in one of the numeric field\n"; generic_client_usage(); } int usage() { _usage(); return 1; } void usage_exit() { _usage(); exit(1); } enum { OPT_NO_CMD = 0, OPT_USER_CREATE, OPT_USER_INFO, OPT_USER_MODIFY, OPT_USER_RM, OPT_USER_SUSPEND, OPT_USER_ENABLE, OPT_SUBUSER_CREATE, OPT_SUBUSER_MODIFY, OPT_SUBUSER_RM, OPT_KEY_CREATE, OPT_KEY_RM, OPT_BUCKETS_LIST, OPT_BUCKET_LINK, OPT_BUCKET_UNLINK, OPT_BUCKET_STATS, OPT_POLICY, OPT_POOL_ADD, OPT_POOL_RM, OPT_POOLS_LIST, OPT_LOG_LIST, OPT_LOG_SHOW, OPT_LOG_RM, OPT_TEMP_REMOVE, }; static uint32_t str_to_perm(const char *str) { if (strcasecmp(str, "read") == 0) return RGW_PERM_READ; else if (strcasecmp(str, "write") == 0) return RGW_PERM_WRITE; else if (strcasecmp(str, "readwrite") == 0) return RGW_PERM_READ | RGW_PERM_WRITE; else if (strcasecmp(str, "full") == 0) return RGW_PERM_FULL_CONTROL; usage_exit(); return 0; // unreachable } struct rgw_flags_desc { uint32_t mask; const char *str; }; static struct rgw_flags_desc rgw_perms[] = { { RGW_PERM_FULL_CONTROL, "full-control" }, { RGW_PERM_READ | RGW_PERM_WRITE, "read-write" }, { RGW_PERM_READ, "read" }, { RGW_PERM_WRITE, "write" }, { RGW_PERM_READ_ACP, "read-acp" }, { RGW_PERM_WRITE_ACP, "read-acp" }, { 0, NULL } }; static void perm_to_str(uint32_t mask, char *buf, int len) { const char *sep = ""; int pos = 0; if (!mask) { snprintf(buf, len, ""); return; } while (mask) { uint32_t orig_mask = mask; for (int i = 0; rgw_perms[i].mask; i++) { struct rgw_flags_desc *desc = &rgw_perms[i]; if ((mask & desc->mask) == desc->mask) { pos += snprintf(buf + pos, len - pos, "%s%s", sep, desc->str); if (pos == len) return; sep = ", "; mask &= ~desc->mask; if (!mask) return; } } if (mask == orig_mask) // no change break; } } static int get_cmd(const char *cmd, const char *prev_cmd, bool *need_more) { *need_more = false; if (strcmp(cmd, "user") == 0 || strcmp(cmd, "subuser") == 0 || strcmp(cmd, "key") == 0 || strcmp(cmd, "buckets") == 0 || strcmp(cmd, "bucket") == 0 || strcmp(cmd, "pool") == 0 || strcmp(cmd, "pools") == 0 || strcmp(cmd, "log") == 0 || strcmp(cmd, "temp") == 0) { *need_more = true; return 0; } if (strcmp(cmd, "policy") == 0) return OPT_POLICY; if (!prev_cmd) return -EINVAL; if (strcmp(prev_cmd, "user") == 0) { if (strcmp(cmd, "create") == 0) return OPT_USER_CREATE; if (strcmp(cmd, "info") == 0) return OPT_USER_INFO; if (strcmp(cmd, "modify") == 0) return OPT_USER_MODIFY; if (strcmp(cmd, "rm") == 0) return OPT_USER_RM; if (strcmp(cmd, "suspend") == 0) return OPT_USER_SUSPEND; if (strcmp(cmd, "enable") == 0) return OPT_USER_ENABLE; } else if (strcmp(prev_cmd, "subuser") == 0) { if (strcmp(cmd, "create") == 0) return OPT_SUBUSER_CREATE; if (strcmp(cmd, "modify") == 0) return OPT_SUBUSER_MODIFY; if (strcmp(cmd, "rm") == 0) return OPT_SUBUSER_RM; } else if (strcmp(prev_cmd, "key") == 0) { if (strcmp(cmd, "create") == 0) return OPT_KEY_CREATE; if (strcmp(cmd, "rm") == 0) return OPT_KEY_RM; } else if (strcmp(prev_cmd, "buckets") == 0) { if (strcmp(cmd, "list") == 0) return OPT_BUCKETS_LIST; } else if (strcmp(prev_cmd, "bucket") == 0) { if (strcmp(cmd, "list") == 0) return OPT_BUCKETS_LIST; if (strcmp(cmd, "link") == 0) return OPT_BUCKET_LINK; if (strcmp(cmd, "unlink") == 0) return OPT_BUCKET_UNLINK; if (strcmp(cmd, "stats") == 0) return OPT_BUCKET_STATS; } else if (strcmp(prev_cmd, "log") == 0) { if (strcmp(cmd, "list") == 0) return OPT_LOG_LIST; if (strcmp(cmd, "show") == 0) return OPT_LOG_SHOW; if (strcmp(cmd, "rm") == 0) return OPT_LOG_RM; } else if (strcmp(prev_cmd, "temp") == 0) { if (strcmp(cmd, "remove") == 0) return OPT_TEMP_REMOVE; } else if (strcmp(prev_cmd, "pool") == 0) { if (strcmp(cmd, "add") == 0) return OPT_POOL_ADD; if (strcmp(cmd, "rm") == 0) return OPT_POOL_RM; } else if (strcmp(prev_cmd, "pools") == 0) { if (strcmp(cmd, "list") == 0) return OPT_POOLS_LIST; } return -EINVAL; } string escape_str(string& src, char c) { int pos = 0; string s = src; string dest; do { int new_pos = src.find(c, pos); if (new_pos >= 0) { dest += src.substr(pos, new_pos - pos); dest += "\\"; dest += c; } else { dest += src.substr(pos); return dest; } pos = new_pos + 1; } while (pos < (int)src.size()); return dest; } static void show_user_info(RGWUserInfo& info, Formatter *formatter) { map::iterator kiter; map::iterator uiter; formatter->open_object_section("user_info"); formatter->dump_string("user_id", info.user_id.c_str()); formatter->dump_int("rados_uid", info.auid); formatter->dump_string("display_name", info.display_name.c_str()); formatter->dump_string("email", info.user_email.c_str()); formatter->dump_int("suspended", (int)info.suspended); // subusers formatter->open_array_section("subusers"); for (uiter = info.subusers.begin(); uiter != info.subusers.end(); ++uiter) { RGWSubUser& u = uiter->second; formatter->open_object_section("user"); formatter->dump_format("id", "%s:%s", info.user_id.c_str(), u.name.c_str()); char buf[256]; perm_to_str(u.perm_mask, buf, sizeof(buf)); formatter->dump_string("permissions", buf); formatter->close_section(); formatter->flush(cout); } formatter->close_section(); // keys formatter->open_array_section("keys"); for (kiter = info.access_keys.begin(); kiter != info.access_keys.end(); ++kiter) { RGWAccessKey& k = kiter->second; const char *sep = (k.subuser.empty() ? "" : ":"); const char *subuser = (k.subuser.empty() ? "" : k.subuser.c_str()); formatter->open_object_section("key"); formatter->dump_format("user", "%s%s%s", info.user_id.c_str(), sep, subuser); formatter->dump_string("access_key", k.id); formatter->dump_string("secret_key", k.key); formatter->close_section(); } formatter->close_section(); formatter->open_array_section("swift_keys"); for (kiter = info.swift_keys.begin(); kiter != info.swift_keys.end(); ++kiter) { RGWAccessKey& k = kiter->second; const char *sep = (k.subuser.empty() ? "" : ":"); const char *subuser = (k.subuser.empty() ? "" : k.subuser.c_str()); formatter->open_object_section("key"); formatter->dump_format("user", "%s%s%s", info.user_id.c_str(), sep, subuser); formatter->dump_string("secret_key", k.key); formatter->close_section(); } formatter->close_section(); formatter->close_section(); formatter->flush(cout); cout << std::endl; } static int create_bucket(string bucket_str, string& user_id, string& display_name, uint64_t auid) { RGWAccessControlPolicy policy, old_policy; map attrs; bufferlist aclbl; string no_oid; rgw_obj obj; RGWBucketInfo bucket_info; int ret; // defaule policy (private) policy.create_default(user_id, display_name); policy.encode(aclbl); ret = rgwstore->get_bucket_info(NULL, bucket_str, bucket_info); if (ret < 0) return ret; rgw_bucket& bucket = bucket_info.bucket; ret = rgwstore->create_bucket(user_id, bucket, attrs, false, auid); if (ret && ret != -EEXIST) goto done; obj.init(bucket, no_oid); ret = rgwstore->set_attr(NULL, obj, RGW_ATTR_ACL, aclbl); if (ret < 0) { cerr << "couldn't set acl on bucket" << std::endl; } ret = rgw_add_bucket(user_id, bucket); dout(20) << "ret=" << ret << dendl; if (ret == -EEXIST) ret = 0; done: return ret; } static void remove_old_indexes(RGWUserInfo& old_info, RGWUserInfo new_info) { int ret; bool success = true; if (!old_info.user_id.empty() && old_info.user_id.compare(new_info.user_id) != 0) { ret = rgw_remove_uid_index(old_info.user_id); if (ret < 0 && ret != -ENOENT) { cerr << "ERROR: could not remove index for uid " << old_info.user_id << " return code: " << ret << std::endl; success = false; } } if (!old_info.user_email.empty() && old_info.user_email.compare(new_info.user_email) != 0) { ret = rgw_remove_email_index(old_info.user_email); if (ret < 0 && ret != -ENOENT) { cerr << "ERROR: could not remove index for email " << old_info.user_email << " return code: " << ret << std::endl; success = false; } } map::iterator old_iter; for (old_iter = old_info.swift_keys.begin(); old_iter != old_info.swift_keys.end(); ++old_iter) { RGWAccessKey& swift_key = old_iter->second; map::iterator new_iter = new_info.swift_keys.find(swift_key.id); if (new_iter == new_info.swift_keys.end()) { ret = rgw_remove_swift_name_index(swift_key.id); if (ret < 0 && ret != -ENOENT) { cerr << "ERROR: could not remove index for swift_name " << swift_key.id << " return code: " << ret << std::endl; success = false; } } } /* we're not removing access keys here.. keys are removed explicitly using the key rm command and removing the old key index is handled there */ if (!success) cerr << "ERROR: this should be fixed manually!" << std::endl; } int bucket_stats(rgw_bucket& bucket, Formatter *formatter) { RGWBucketInfo bucket_info; int r = rgwstore->get_bucket_info(NULL, bucket.name, bucket_info); if (r < 0) return r; map stats; int ret = rgwstore->get_bucket_stats(bucket, stats); if (ret < 0) { cerr << "error getting bucket stats ret=" << ret << std::endl; return ret; } map::iterator iter; formatter->open_object_section("stats"); formatter->dump_string("bucket", bucket.name.c_str()); formatter->dump_string("pool", bucket.pool.c_str()); formatter->dump_int("id", bucket.bucket_id); formatter->dump_string("marker", bucket.marker.c_str()); formatter->dump_string("owner", bucket_info.owner.c_str()); formatter->open_object_section("usage"); for (iter = stats.begin(); iter != stats.end(); ++iter) { RGWBucketStats& s = iter->second; const char *cat_name = rgw_obj_category_name(iter->first); formatter->open_object_section(cat_name); formatter->dump_int("size_kb", s.num_kb); formatter->dump_int("size_kb_actual", s.num_kb_rounded); formatter->dump_int("num_objects", s.num_objects); formatter->close_section(); formatter->flush(cout); } formatter->close_section(); formatter->close_section(); return 0; } enum ObjectKeyType { KEY_TYPE_SWIFT, KEY_TYPE_S3, }; int main(int argc, char **argv) { vector args; argv_to_vec(argc, (const char **)argv, args); env_to_vec(args); global_init(args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); common_init_finish(g_ceph_context); std::string user_id, access_key, secret_key, user_email, display_name; std::string bucket_name, pool_name, object; std::string date, time, subuser, access, format; std::string key_type_str; ObjectKeyType key_type = KEY_TYPE_S3; rgw_bucket bucket; uint32_t perm_mask = 0; uint64_t auid = -1; RGWUserInfo info; RGWAccess *store; int opt_cmd = OPT_NO_CMD; bool need_more; int gen_secret = false; int gen_key = false; bool implicit_gen_secret = true; bool implicit_gen_key = true; char secret_key_buf[SECRET_KEY_LEN + 1]; char public_id_buf[PUBLIC_ID_LEN + 1]; bool user_modify_op; int64_t bucket_id = -1; Formatter *formatter = NULL; int purge_data = false; RGWBucketInfo bucket_info; int pretty_format = false; int show_log_entries = true; int show_log_sum = true; int skip_zero_entries = false; // log show int purge_keys = false; std::string val; std::ostringstream errs; long long tmp = 0; for (std::vector::iterator i = args.begin(); i != args.end(); ) { if (ceph_argparse_double_dash(args, i)) { break; } else if (ceph_argparse_flag(args, i, "-h", "--help", (char*)NULL)) { usage(); return 0; } else if (ceph_argparse_witharg(args, i, &val, "-i", "--uid", (char*)NULL)) { user_id = val; } else if (ceph_argparse_witharg(args, i, &val, "--access-key", (char*)NULL)) { access_key = val; } else if (ceph_argparse_witharg(args, i, &val, "--subuser", (char*)NULL)) { subuser = val; } else if (ceph_argparse_witharg(args, i, &val, "--secret", (char*)NULL)) { secret_key = val; } else if (ceph_argparse_witharg(args, i, &val, "-e", "--email", (char*)NULL)) { user_email = val; } else if (ceph_argparse_witharg(args, i, &val, "-n", "--display-name", (char*)NULL)) { display_name = val; } else if (ceph_argparse_witharg(args, i, &val, "-b", "--bucket", (char*)NULL)) { bucket_name = val; } else if (ceph_argparse_witharg(args, i, &val, "-p", "--pool", (char*)NULL)) { 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, "--key-type", (char*)NULL)) { key_type_str = val; if (key_type_str.compare("swift") == 0) { key_type = KEY_TYPE_SWIFT; } else if (key_type_str.compare("s3") == 0) { key_type = KEY_TYPE_S3; } else { cerr << "bad key type: " << key_type_str << std::endl; return usage(); } } else if (ceph_argparse_binary_flag(args, i, &gen_key, NULL, "--gen-access-key", (char*)NULL)) { implicit_gen_key = false; } else if (ceph_argparse_binary_flag(args, i, &gen_secret, NULL, "--gen-secret", (char*)NULL)) { implicit_gen_secret = false; } else if (ceph_argparse_binary_flag(args, i, &show_log_entries, NULL, "--show_log_entries", (char*)NULL)) { // do nothing } else if (ceph_argparse_binary_flag(args, i, &show_log_sum, NULL, "--show_log_sum", (char*)NULL)) { // do nothing } else if (ceph_argparse_binary_flag(args, i, &skip_zero_entries, NULL, "--skip_zero_entries", (char*)NULL)) { // do nothing } else if (ceph_argparse_withlonglong(args, i, &tmp, &errs, "-a", "--auth-uid", (char*)NULL)) { if (!errs.str().empty()) { cerr << errs.str() << std::endl; exit(EXIT_FAILURE); } auid = tmp; } else if (ceph_argparse_witharg(args, i, &val, "--date", (char*)NULL)) { date = val; } else if (ceph_argparse_witharg(args, i, &val, "--time", (char*)NULL)) { time = val; } else if (ceph_argparse_witharg(args, i, &val, "--access", (char*)NULL)) { access = val; perm_mask = str_to_perm(access.c_str()); } else if (ceph_argparse_withlonglong(args, i, &tmp, &errs, "--bucket-id", (char*)NULL)) { if (!errs.str().empty()) { cerr << errs.str() << std::endl; exit(EXIT_FAILURE); } bucket_id = tmp; if (bucket_id < 0) { cerr << "bad bucket-id: " << bucket_id << std::endl; return usage(); } } else if (ceph_argparse_witharg(args, i, &val, "--format", (char*)NULL)) { format = val; } else if (ceph_argparse_binary_flag(args, i, &pretty_format, NULL, "--pretty-format", (char*)NULL)) { // do nothing } else if (ceph_argparse_binary_flag(args, i, &purge_data, NULL, "--purge-data", (char*)NULL)) { // do nothing } else if (ceph_argparse_binary_flag(args, i, &purge_keys, NULL, "--purge-keys", (char*)NULL)) { // do nothing } else { ++i; } } if (args.size() == 0) { return usage(); } else { const char *prev_cmd = NULL; for (std::vector::iterator i = args.begin(); i != args.end(); ++i) { opt_cmd = get_cmd(*i, prev_cmd, &need_more); if (opt_cmd < 0) { cerr << "unrecognized arg " << *i << std::endl; return usage(); } if (!need_more) break; prev_cmd = *i; } if (opt_cmd == OPT_NO_CMD) return usage(); } // default to pretty json if (format.empty()) { format = "json"; pretty_format = true; } if (format == "xml") formatter = new XMLFormatter(pretty_format); else if (format == "json") formatter = new JSONFormatter(pretty_format); else { cerr << "unrecognized format: " << format << std::endl; return usage(); } if (!subuser.empty()) { char *suser = strdup(subuser.c_str()); char *p = strchr(suser, ':'); if (p) { *p = '\0'; if (!user_id.empty()) { if (user_id != suser) { cerr << "bad subuser " << subuser << " for uid " << user_id << std::endl; return 1; } } else { user_id = suser; } subuser = p + 1; } free(suser); } if (opt_cmd == OPT_KEY_RM && key_type == KEY_TYPE_S3 && access_key.empty()) { cerr << "error: access key was not specified" << std::endl; return usage(); } 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_USER_RM); RGWStoreManager store_manager; store = store_manager.init("rados", g_ceph_context); if (!store) { cerr << "couldn't init storage provider" << std::endl; return 5; //EIO } if (opt_cmd != OPT_USER_CREATE && opt_cmd != OPT_LOG_SHOW && opt_cmd != OPT_LOG_LIST && opt_cmd != OPT_LOG_RM && user_id.empty()) { bool found = false; string s; if (!found && (!user_email.empty())) { s = user_email; if (rgw_get_user_info_by_email(s, info) >= 0) { found = true; } else { cerr << "could not find user by specified email" << std::endl; } } if (!found && (!access_key.empty())) { s = access_key; if (rgw_get_user_info_by_access_key(s, info) >= 0) { found = true; } else { cerr << "could not find user by specified access key" << std::endl; } } if (found) user_id = info.user_id.c_str(); } if (user_modify_op || opt_cmd == OPT_USER_CREATE || opt_cmd == OPT_USER_INFO || opt_cmd == OPT_BUCKET_UNLINK || opt_cmd == OPT_BUCKET_LINK || opt_cmd == OPT_USER_SUSPEND || opt_cmd == OPT_USER_ENABLE) { if (user_id.empty()) { cerr << "user_id was not specified, aborting" << std::endl; return usage(); } bool found = (rgw_get_user_info_by_uid(user_id, info) >= 0); if (opt_cmd == OPT_USER_CREATE) { if (found) { cerr << "error: user already exists" << std::endl; return 1; } } else if (!found) { cerr << "error reading user info, aborting" << std::endl; return 1; } } if (opt_cmd == OPT_SUBUSER_CREATE || opt_cmd == OPT_SUBUSER_MODIFY || opt_cmd == OPT_SUBUSER_RM) { if (subuser.empty()) { cerr << "subuser creation was requires specifying subuser name" << std::endl; return 1; } map::iterator iter = info.subusers.find(subuser); bool found = (iter != info.subusers.end()); if (opt_cmd == OPT_SUBUSER_CREATE) { if (found) { cerr << "error: subuser already exists" << std::endl; return 1; } } else if (!found) { cerr << "error: subuser doesn't exist" << std::endl; return 1; } } bool keys_not_requested = (access_key.empty() && secret_key.empty() && !gen_secret && !gen_key && opt_cmd != OPT_KEY_CREATE); if (opt_cmd == OPT_USER_CREATE || (user_modify_op && !keys_not_requested)) { int ret; if (opt_cmd == OPT_USER_CREATE && display_name.empty()) { cerr << "display name was not specified, aborting" << std::endl; return 0; } if ((secret_key.empty() && implicit_gen_secret) || gen_secret) { ret = gen_rand_base64(secret_key_buf, sizeof(secret_key_buf)); if (ret < 0) { cerr << "aborting" << std::endl; return 1; } secret_key = secret_key_buf; } if ((access_key.empty() && implicit_gen_key) || gen_key) { RGWUserInfo duplicate_check; string duplicate_check_id; do { ret = gen_rand_alphanumeric_upper(public_id_buf, sizeof(public_id_buf)); if (ret < 0) { cerr << "aborting" << std::endl; return 1; } access_key = public_id_buf; duplicate_check_id = access_key; } while (!rgw_get_user_info_by_access_key(duplicate_check_id, duplicate_check)); } } map::iterator kiter; map::iterator uiter; RGWUserInfo old_info = info; if ((!bucket_name.empty()) || bucket_id >= 0) { if (bucket_id >= 0) { char bucket_char[16]; snprintf(bucket_char, sizeof(bucket_char), ".%lld", (long long unsigned)bucket_id); string bucket_string(bucket_char); int ret = rgwstore->get_bucket_info(NULL, bucket_string, 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; } } int err; switch (opt_cmd) { case OPT_USER_CREATE: case OPT_USER_MODIFY: case OPT_SUBUSER_CREATE: case OPT_SUBUSER_MODIFY: case OPT_KEY_CREATE: if (!user_id.empty()) info.user_id = user_id; if (key_type == KEY_TYPE_SWIFT) { access_key = info.user_id; access_key.append(":"); access_key.append(subuser); } if ((!access_key.empty()) && (!secret_key.empty())) { RGWAccessKey k; k.id = access_key; k.key = secret_key; if (!subuser.empty()) k.subuser = subuser; if (key_type == KEY_TYPE_SWIFT) info.swift_keys[access_key] = k; else info.access_keys[access_key] = k; } else if (opt_cmd == OPT_KEY_CREATE && (access_key.empty() || secret_key.empty())) { if (key_type == KEY_TYPE_SWIFT) cerr << "swift key modification requires both subuser and secret key" << std::endl; else cerr << "access key modification requires both access key and secret key" << std::endl; return 1; } if (!display_name.empty()) info.display_name = display_name; if (!user_email.empty()) info.user_email = user_email; if (auid != (uint64_t)-1) info.auid = auid; if (!subuser.empty()) { RGWSubUser u; u.name = subuser; u.perm_mask = perm_mask; info.subusers[subuser] = u; } if ((err = rgw_store_user_info(info, false)) < 0) { cerr << "error storing user info: " << cpp_strerror(-err) << std::endl; break; } remove_old_indexes(old_info, info); show_user_info(info, formatter); break; case OPT_SUBUSER_RM: uiter = info.subusers.find(subuser); assert (uiter != info.subusers.end()); info.subusers.erase(uiter); if (purge_keys) { map *keys_map; access_key = info.user_id; access_key.append(":"); access_key.append(subuser); keys_map = &info.swift_keys; kiter = keys_map->find(access_key); if (kiter != keys_map->end()) { rgw_remove_key_index(kiter->second); keys_map->erase(kiter); } } if ((err = rgw_store_user_info(info, false)) < 0) { cerr << "error storing user info: " << cpp_strerror(-err) << std::endl; break; } remove_old_indexes(old_info, info); show_user_info(info, formatter); break; case OPT_KEY_RM: { map *keys_map; if (key_type == KEY_TYPE_SWIFT) { access_key = info.user_id; access_key.append(":"); access_key.append(subuser); keys_map = &info.swift_keys; } else { keys_map = &info.access_keys; } kiter = keys_map->find(access_key); if (kiter == keys_map->end()) { cerr << "key not found" << std::endl; } else { rgw_remove_key_index(kiter->second); keys_map->erase(kiter); if ((err = rgw_store_user_info(info, false)) < 0) { cerr << "error storing user info: " << cpp_strerror(-err) << std::endl; break; } } } show_user_info(info, formatter); break; case OPT_USER_INFO: show_user_info(info, formatter); break; } if (opt_cmd == OPT_POLICY) { bufferlist bl; rgw_obj obj(bucket, object); int ret = store->get_attr(NULL, obj, RGW_ATTR_ACL, bl); RGWAccessControlPolicy_S3 policy; if (ret >= 0) { bufferlist::iterator iter = bl.begin(); try { policy.decode(iter); } catch (buffer::error& err) { dout(0) << "ERROR: caught buffer::error, could not decode policy" << dendl; return -EIO; } policy.to_xml(cout); cout << std::endl; } } if (opt_cmd == OPT_BUCKETS_LIST) { RGWAccessHandle handle; formatter->reset(); formatter->open_array_section("buckets"); if (!user_id.empty()) { RGWUserBuckets buckets; if (rgw_read_user_buckets(user_id, buckets, false) < 0) { cerr << "list buckets: could not get buckets for uid " << user_id << std::endl; } else { map& m = buckets.get_buckets(); map::iterator iter; for (iter = m.begin(); iter != m.end(); ++iter) { RGWBucketEnt obj = iter->second; formatter->dump_string("bucket", obj.bucket.name); } } } else { if (store->list_buckets_init(&handle) < 0) { cerr << "list buckets: no buckets found" << std::endl; } else { RGWObjEnt obj; while (store->list_buckets_next(obj, &handle) >= 0) { formatter->dump_string("bucket", obj.name); } } } formatter->close_section(); formatter->flush(cout); cout << std::endl; } if (opt_cmd == OPT_BUCKET_LINK) { if (bucket_name.empty()) { cerr << "bucket name was not specified" << std::endl; return usage(); } string uid_str(user_id); string no_oid; bufferlist aclbl; rgw_obj obj(bucket, no_oid); int r = rgwstore->get_attr(NULL, obj, RGW_ATTR_ACL, aclbl); if (r >= 0) { RGWAccessControlPolicy policy; ACLOwner owner; try { bufferlist::iterator iter = aclbl.begin(); ::decode(policy, iter); owner = policy.get_owner(); } catch (buffer::error& err) { dout(10) << "couldn't decode policy" << dendl; return -EINVAL; } //cout << "bucket is linked to user '" << owner.get_id() << "'.. unlinking" << std::endl; r = rgw_remove_user_bucket_info(owner.get_id(), bucket); if (r < 0) { cerr << "could not unlink policy from user '" << owner.get_id() << "'" << std::endl; return r; } } r = create_bucket(bucket_name.c_str(), uid_str, info.display_name, info.auid); if (r < 0) cerr << "error linking bucket to user: r=" << r << std::endl; return -r; } if (opt_cmd == OPT_BUCKET_UNLINK) { if (bucket_name.empty()) { cerr << "bucket name was not specified" << std::endl; return usage(); } int r = rgw_remove_user_bucket_info(user_id, bucket); if (r < 0) cerr << "error unlinking bucket " << cpp_strerror(-r) << std::endl; return -r; } if (opt_cmd == OPT_TEMP_REMOVE) { if (date.empty()) { cerr << "date wasn't specified" << std::endl; return usage(); } int r = store->remove_temp_objects(date, time); if (r < 0) { cerr << "failure removing temp objects: " << cpp_strerror(r) << std::endl; return 1; } } if (opt_cmd == OPT_LOG_LIST) { // filter by date? if (date.size() && date.size() != 10) { cerr << "bad date format for '" << date << "', expect YYYY-MM-DD" << std::endl; return -EINVAL; } formatter->reset(); formatter->open_array_section("logs"); RGWAccessHandle h; int r = store->log_list_init(date, &h); if (r == -ENOENT) { // no logs. } else { if (r < 0) { cerr << "log list: error " << r << std::endl; return r; } while (true) { string name; int r = store->log_list_next(h, &name); if (r == -ENOENT) break; if (r < 0) { cerr << "log list: error " << r << std::endl; return r; } formatter->dump_string("object", name); } } formatter->close_section(); formatter->flush(cout); cout << std::endl; } if (opt_cmd == OPT_LOG_SHOW || opt_cmd == OPT_LOG_RM) { if (object.empty() && (date.empty() || bucket_name.empty() || bucket_id < 0)) { cerr << "object or (at least one of date, bucket, bucket-id) were not specified" << std::endl; return usage(); } string oid; if (!object.empty()) { oid = object; } else { char buf[16]; snprintf(buf, sizeof(buf), "%lld", (unsigned long long)bucket_id); oid = date; oid += "-"; oid += buf; oid += "-"; oid += string(bucket.name); } if (opt_cmd == OPT_LOG_SHOW) { RGWAccessHandle h; int r = store->log_show_init(oid, &h); if (r < 0) { cerr << "error opening log " << oid << ": " << cpp_strerror(-r) << std::endl; return -r; } formatter->reset(); formatter->open_object_section("log"); struct rgw_log_entry entry; // peek at first entry to get bucket metadata r = store->log_show_next(h, &entry); if (r < 0) { cerr << "error reading log " << oid << ": " << cpp_strerror(-r) << std::endl; return -r; } formatter->dump_int("bucket_id", entry.bucket_id); formatter->dump_string("bucket_owner", entry.bucket_owner); formatter->dump_string("bucket", entry.bucket); uint64_t agg_time = 0; uint64_t agg_bytes_sent = 0; uint64_t agg_bytes_received = 0; uint64_t total_entries = 0; if (show_log_entries) formatter->open_array_section("log_entries"); do { uint64_t total_time = entry.total_time.sec() * 1000000LL * entry.total_time.usec(); agg_time += total_time; agg_bytes_sent += entry.bytes_sent; agg_bytes_received += entry.bytes_received; total_entries++; if (skip_zero_entries && entry.bytes_sent == 0 && entry.bytes_received == 0) goto next; if (show_log_entries) { formatter->open_object_section("log_entry"); formatter->dump_string("bucket", entry.bucket.c_str()); entry.time.gmtime(formatter->dump_stream("time")); // UTC entry.time.localtime(formatter->dump_stream("time_local")); formatter->dump_string("remote_addr", entry.remote_addr.c_str()); if (entry.object_owner.length()) formatter->dump_string("object_owner", entry.object_owner.c_str()); formatter->dump_string("user", entry.user.c_str()); formatter->dump_string("operation", entry.op.c_str()); formatter->dump_string("uri", entry.uri.c_str()); formatter->dump_string("http_status", entry.http_status.c_str()); formatter->dump_string("error_code", entry.error_code.c_str()); formatter->dump_int("bytes_sent", entry.bytes_sent); formatter->dump_int("bytes_received", entry.bytes_received); formatter->dump_int("object_size", entry.obj_size); formatter->dump_int("total_time", total_time); formatter->dump_string("user_agent", entry.user_agent.c_str()); formatter->dump_string("referrer", entry.referrer.c_str()); formatter->close_section(); formatter->flush(cout); } next: r = store->log_show_next(h, &entry); } while (r > 0); if (r < 0) { cerr << "error reading log " << oid << ": " << cpp_strerror(-r) << std::endl; return -r; } if (show_log_entries) formatter->close_section(); if (show_log_sum) { formatter->open_object_section("log_sum"); formatter->dump_int("bytes_sent", agg_bytes_sent); formatter->dump_int("bytes_received", agg_bytes_received); formatter->dump_int("total_time", agg_time); formatter->dump_int("total_entries", total_entries); formatter->close_section(); } formatter->close_section(); formatter->flush(cout); cout << std::endl; } if (opt_cmd == OPT_LOG_RM) { int r = store->log_remove(oid); if (r < 0) { cerr << "error removing log " << oid << ": " << cpp_strerror(-r) << std::endl; return -r; } } } if (opt_cmd == OPT_USER_RM) { rgw_delete_user(info); } if (opt_cmd == OPT_POOL_ADD) { if (pool_name.empty()) { cerr << "need to specify pool to add!" << std::endl; return usage(); } int ret = rgwstore->add_bucket_placement(pool_name); if (ret < 0) cerr << "failed to add bucket placement: " << cpp_strerror(-ret) << std::endl; } if (opt_cmd == OPT_POOL_RM) { if (pool_name.empty()) { cerr << "need to specify pool to remove!" << std::endl; return usage(); } int ret = rgwstore->remove_bucket_placement(pool_name); if (ret < 0) cerr << "failed to remove bucket placement: " << cpp_strerror(-ret) << std::endl; } if (opt_cmd == OPT_POOLS_LIST) { set pools; int ret = rgwstore->list_placement_set(pools); if (ret < 0) { cerr << "could not list placement set: " << cpp_strerror(-ret) << std::endl; return ret; } formatter->reset(); formatter->open_array_section("pools"); set::iterator siter; for (siter = pools.begin(); siter != pools.end(); ++siter) { formatter->open_object_section("pool"); formatter->dump_string("name", *siter); formatter->close_section(); } formatter->close_section(); formatter->flush(cout); cout << std::endl; } if (opt_cmd == OPT_BUCKET_STATS) { if (bucket_name.empty() && bucket_id < 0 && user_id.empty()) { cerr << "either bucket or bucket-id or uid needs to be specified" << std::endl; return usage(); } formatter->reset(); if (user_id.empty()) { bucket_stats(bucket, formatter); } else { RGWUserBuckets buckets; if (rgw_read_user_buckets(user_id, buckets, false) < 0) { cerr << "could not get buckets for uid " << user_id << std::endl; } else { formatter->open_array_section("buckets"); map& m = buckets.get_buckets(); for (map::iterator iter = m.begin(); iter != m.end(); ++iter) { RGWBucketEnt obj = iter->second; bucket_stats(obj.bucket, formatter); } formatter->close_section(); } } formatter->flush(cout); cout << std::endl; } if (opt_cmd == OPT_USER_SUSPEND || opt_cmd == OPT_USER_ENABLE) { string id; __u8 disable = (opt_cmd == OPT_USER_SUSPEND ? 1 : 0); if (user_id.empty()) { cerr << "uid was not specified" << std::endl; return usage(); } RGWUserBuckets buckets; if (rgw_read_user_buckets(user_id, buckets, false) < 0) { cerr << "could not get buckets for uid " << user_id << std::endl; } map& m = buckets.get_buckets(); map::iterator iter; int ret; info.suspended = disable; ret = rgw_store_user_info(info, false); if (ret < 0) { cerr << "ERROR: failed to store user info user=" << user_id << " ret=" << ret << std::endl; return 1; } if (disable) dout(0) << "disabling user buckets" << dendl; else dout(0) << "enabling user buckets" << dendl; vector bucket_names; for (iter = m.begin(); iter != m.end(); ++iter) { RGWBucketEnt obj = iter->second; bucket_names.push_back(obj.bucket); } ret = rgwstore->set_buckets_enabled(bucket_names, !disable); if (ret < 0) { cerr << "ERROR: failed to change pool" << std::endl; return 1; } } return 0; }