virtual int set_attr(std::string& bucket, std::string& obj,
const char *name, bufferlist& bl) = 0;
+ virtual int get_bucket_id(std::string& bucket) { return -ENOTSUP; }
+
/**
* stat an object
*/
#include "rgw_access.h"
#include "rgw_acl.h"
#include "rgw_log.h"
+#include "rgw_formats.h"
#include "auth/Crypto.h"
#define SECRET_KEY_LEN 40
#define PUBLIC_ID_LEN 20
+static RGWFormatter_Plain formatter_plain;
+static RGWFormatter_XML formatter_xml;
+static RGWFormatter_JSON formatter_json;
+
void usage()
{
cerr << "usage: radosgw_admin <cmd> [options...]" << std::endl;
cerr << " buckets list list buckets\n";
cerr << " bucket link link bucket to specified user\n";
cerr << " bucket unlink unlink bucket from specified user\n";
+ cerr << " pool info show pool information\n";
cerr << " policy read bucket/object policy\n";
cerr << " log show dump a log from specific object or (bucket + date)\n";
cerr << "options:\n";
cerr << " --bucket=<bucket>\n";
cerr << " --object=<object>\n";
cerr << " --date=<yyyy-mm-dd>\n";
+ cerr << " --pool-id=<pool-id>\n";
+ cerr << " --format=<format> specify output format for certain operations: xml,\n";
+ cerr << " json, plain\n";
generic_client_usage();
exit(1);
}
OPT_BUCKET_LINK,
OPT_BUCKET_UNLINK,
OPT_POLICY,
+ OPT_POOL_INFO,
OPT_LOG_SHOW,
};
strcmp(cmd, "key") == 0 ||
strcmp(cmd, "buckets") == 0 ||
strcmp(cmd, "bucket") == 0 ||
+ strcmp(cmd, "pool") == 0 ||
strcmp(cmd, "log") == 0) {
*need_more = true;
return 0;
} else if (strcmp(prev_cmd, "log") == 0) {
if (strcmp(cmd, "show") == 0)
return OPT_LOG_SHOW;
+ } else if (strcmp(prev_cmd, "pool") == 0) {
+ if (strcmp(cmd, "info") == 0)
+ return OPT_POOL_INFO;
}
return -EINVAL;
char secret_key_buf[SECRET_KEY_LEN + 1];
char public_id_buf[PUBLIC_ID_LEN + 1];
bool user_modify_op;
+ int pool_id = 0;
+ const char *format = 0;
+ RGWFormatter *formatter = &formatter_xml;
FOR_EACH_ARG(args) {
if (CEPH_ARGPARSE_EQ("uid", 'i')) {
} else if (CEPH_ARGPARSE_EQ("access", '\0')) {
CEPH_ARGPARSE_SET_ARG_VAL(&access, OPT_STR);
perm_mask = str_to_perm(access);
+ } else if (CEPH_ARGPARSE_EQ("pool-id", '\0')) {
+ CEPH_ARGPARSE_SET_ARG_VAL(&pool_id, OPT_INT);
+ } else if (CEPH_ARGPARSE_EQ("format", '\0')) {
+ CEPH_ARGPARSE_SET_ARG_VAL(&format, OPT_STR);
} else {
if (!opt_cmd) {
opt_cmd = get_cmd(CEPH_ARGPARSE_VAL, prev_cmd, &need_more);
if (opt_cmd == OPT_NO_CMD)
usage();
+ if (format) {
+ if (strcmp(format, "xml") == 0)
+ formatter = &formatter_xml;
+ else if (strcmp(format, "json") == 0)
+ formatter = &formatter_json;
+ else if (strcmp(format, "plain") == 0)
+ formatter = &formatter_plain;
+ else {
+ cerr << "unrecognized format: " << format << std::endl;
+ usage();
+ }
+ }
+
if (subuser) {
char *suser = strdup(subuser);
char *p = strchr(suser, ':');
rgw_delete_user(info);
}
+ if (opt_cmd == OPT_POOL_INFO) {
+ RGWPoolInfo info;
+ int ret = rgw_retrieve_pool_info(pool_id, info);
+ if (ret < 0) {
+ cerr << "could not retrieve pool info for pool_id=" << pool_id << std::endl;
+ return ret;
+ }
+ formatter->init();
+ formatter->open_obj_section("Pool");
+ formatter->dump_value_int("ID", "%d", pool_id);
+ formatter->dump_value_str("Bucket", "%s", info.bucket.c_str());
+ formatter->dump_value_str("Owner", "%s", info.owner.c_str());
+ formatter->close_section("Pool");
+ formatter->flush(cout);
+ }
+
return 0;
}
free(p);
}
-void RGWFormatter::flush()
+void RGWFormatter::reset()
+{
+ free(buf);
+ buf = NULL;
+ len = 0;
+ max_len = 0;
+}
+
+void RGWFormatter::flush(struct req_state *s)
{
if (!buf)
return;
RGW_LOG(0) << "flush(): buf='" << buf << "' strlen(buf)=" << strlen(buf) << dendl;
CGI_PutStr(s, buf, len - 1);
- free(buf);
- buf = NULL;
- len = 0;
- max_len = 0;
+ reset();
+}
+
+void RGWFormatter::flush(ostream& os)
+{
+ if (!buf)
+ return;
+
+ RGW_LOG(0) << "flush(): buf='" << buf << "' strlen(buf)=" << strlen(buf) << dendl;
+ os << buf << std::endl;
+ reset();
}
};
WRITE_CLASS_ENCODER(RGWUserInfo)
+struct RGWPoolInfo
+{
+ string bucket;
+ string owner;
+
+ void encode(bufferlist& bl) const {
+ __u32 ver = 1;
+ ::encode(ver, bl);
+ ::encode(bucket, bl);
+ ::encode(owner, bl);
+ }
+ void decode(bufferlist::iterator& bl) {
+ __u32 ver;
+ ::decode(ver, bl);
+ ::decode(bucket, bl);
+ ::decode(owner, bl);
+ }
+};
+WRITE_CLASS_ENCODER(RGWPoolInfo)
+
struct req_state;
class RGWFormatter {
protected:
- struct req_state *s;
char *buf;
int len;
int max_len;
public:
RGWFormatter() : buf(NULL), len(0), max_len(0) {}
virtual ~RGWFormatter() {}
- void init(struct req_state *_s) {
- s = _s;
+ void init() {
if (buf)
free(buf);
buf = NULL;
max_len = 0;
formatter_init();
}
+ void reset();
void write_data(const char *fmt, ...);
- virtual void flush();
+ virtual void flush(struct req_state *s);
+ virtual void flush(ostream& os);
virtual int get_len() { return (len ? len - 1 : 0); } // don't include null termination in length
virtual void open_array_section(const char *name) = 0;
virtual void open_obj_section(const char *name) = 0;
utime_t time;
+ int pool_id;
+
req_state() : acl(NULL), os_auth_token(NULL), os_user(NULL), os_groups(NULL) {}
};
entry.http_status = "200"; // default
entry.error_code = s->err.s3_code;
+ entry.pool_id = s->pool_id;
bufferlist bl;
::encode(entry, bl);
localtime_r(&t, &bdt);
char buf[entry.bucket.size() + 16];
- sprintf(buf, "%.4d-%.2d-%.2d-%s", (bdt.tm_year+1900), (bdt.tm_mon+1), bdt.tm_mday, entry.bucket.c_str());
+ sprintf(buf, "%.4d-%.2d-%.2d-%d-%s", (bdt.tm_year+1900), (bdt.tm_mon+1), bdt.tm_mday, s->pool_id, entry.bucket.c_str());
string oid = buf;
int ret = rgwstore->append_async(log_bucket, oid, bl.length(), bl);
#include "rgw_common.h"
#include "include/utime.h"
-#define LOG_ENTRY_VER 2
+#define LOG_ENTRY_VER 3
#define RGW_SHOULD_LOG_DEFAULT 1
utime_t total_time;
string user_agent;
string referrer;
+ uint64_t pool_id;
void encode(bufferlist &bl) const {
uint8_t ver;
::encode(user_agent, bl);
::encode(referrer, bl);
::encode(bytes_received, bl);
+ ::encode(pool_id, bl);
}
void decode(bufferlist::iterator &p) {
uint8_t ver;
::decode(bytes_received, p);
else
bytes_received = 0;
+
+ if (ver >= 3)
+ ::decode(pool_id, p);
+ else
+ pool_id = -1;
}
};
WRITE_CLASS_ENCODER(rgw_log_entry)
bufferlist aclbl;
bool existed;
bool pol_ret;
+ int pool_id;
int r = get_policy_from_attr(&old_policy, rgw_root_bucket, s->bucket_str);
if (r >= 0) {
if (ret == -EEXIST)
ret = 0;
+ pool_id = rgwstore->get_bucket_id(s->bucket_str);
+ if (pool_id >= 0) {
+ s->pool_id = pool_id;
+ RGWPoolInfo info;
+ info.owner = s->user.user_id;
+ info.bucket = s->bucket_str;
+ rgw_store_pool_info(pool_id, info);
+ }
+
done:
send_response();
}
ret = -EACCES;
}
+ if (!s->bucket_str.empty())
+ s->pool_id = rgwstore->get_bucket_id(s->bucket_str);
return ret;
}
return r;
}
+int RGWRados::get_bucket_id(std::string& bucket)
+{
+ librados::IoCtx io_ctx;
+ int r = open_bucket_ctx(bucket, io_ctx);
+ if (r < 0)
+ return r;
+ return io_ctx.get_id();
+}
+
int RGWRados::tmap_set(std::string& bucket, std::string& obj, std::string& key, bufferlist& bl)
{
bufferlist cmdbl, emptybl;
virtual int obj_stat(std::string& bucket, std::string& obj, uint64_t *psize, time_t *pmtime);
+ virtual int get_bucket_id(std::string& bucket);
+
virtual bool supports_tmap() { return true; }
virtual int tmap_set(std::string& bucket, std::string& obj, std::string& key, bufferlist& bl);
virtual int tmap_create(std::string& bucket, std::string& obj, std::string& key, bufferlist& bl);
dump_content_length(s, s->formatter->get_len());
}
CGI_PRINTF(s,"Content-type: %s\r\n\r\n", content_type);
- s->formatter->flush();
+ s->formatter->flush(s);
s->header_ended = true;
}
set_req_state_err(s, err_no);
dump_errno(s);
end_header(s);
- s->formatter->flush();
+ s->formatter->flush(s);
}
void dump_continue(struct req_state *s)
}
}
done:
- s->formatter->init(s);
+ s->formatter->init();
}
static void line_unfold(const char *line, string& sdest)
dump_content_length(s, s->formatter->get_len());
end_header(s);
- s->formatter->flush();
+ s->formatter->flush(s);
}
void RGWListBucket_REST_OS::send_response()
s->formatter->close_section("container");
end_header(s);
- s->formatter->flush();
+ s->formatter->flush(s);
}
static void dump_container_metadata(struct req_state *s, RGWBucketEnt& bucket)
end_header(s);
dump_start(s);
- s->formatter->flush();
+ s->formatter->flush(s);
}
void RGWCreateBucket_REST_OS::send_response()
set_req_state_err(s, ret);
dump_errno(s);
end_header(s);
- s->formatter->flush();
+ s->formatter->flush(s);
}
void RGWDeleteBucket_REST_OS::send_response()
set_req_state_err(s, r);
dump_errno(s);
end_header(s);
- s->formatter->flush();
+ s->formatter->flush(s);
}
void RGWPutObj_REST_OS::send_response()
set_req_state_err(s, ret);
dump_errno(s);
end_header(s);
- s->formatter->flush();
+ s->formatter->flush(s);
}
void RGWDeleteObj_REST_OS::send_response()
set_req_state_err(s, r);
dump_errno(s);
end_header(s);
- s->formatter->flush();
+ s->formatter->flush(s);
}
int RGWGetObj_REST_OS::send_response(void *handle)
if (get_data && !orig_ret) {
CGI_PutStr(s, data, len);
}
- s->formatter->flush();
+ s->formatter->flush(s);
return 0;
}
list_all_buckets_end(s);
dump_content_length(s, s->formatter->get_len());
end_header(s, "application/xml");
- s->formatter->flush();
+ s->formatter->flush(s);
}
void RGWListBucket_REST_S3::send_response()
}
}
s->formatter->close_section("ListBucketResult");
- s->formatter->flush();
+ s->formatter->flush(s);
}
void RGWCreateBucket_REST_S3::send_response()
}
}
s->formatter->close_section("CopyObjectResult");
- s->formatter->flush();
+ s->formatter->flush(s);
}
}
static string ui_openstack_bucket = USER_INFO_OPENSTACK_BUCKET_NAME;
static string ui_uid_bucket = USER_INFO_UID_BUCKET_NAME;
+static string pi_pool_bucket = POOL_INFO_BUCKET_NAME;
+
string rgw_root_bucket = RGW_ROOT_BUCKET;
#define READ_CHUNK_LEN (16 * 1024)
return ret;
}
+static int get_obj(string& bucket, string& key, bufferlist& bl)
+{
+ int ret;
+ char *data = NULL;
+ struct rgw_err err;
+ RGWUID uid;
+ void *handle = NULL;
+ bufferlist::iterator iter;
+ int request_len = READ_CHUNK_LEN;
+ ret = rgwstore->prepare_get_obj(bucket, key, 0, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, &handle, &err);
+ if (ret < 0)
+ return ret;
+
+ do {
+ ret = rgwstore->get_obj(&handle, bucket, key, &data, 0, request_len - 1);
+ if (ret < 0)
+ goto done;
+ if (ret < request_len)
+ break;
+ free(data);
+ request_len *= 2;
+ } while (true);
+
+ bl.append(data, ret);
+ free(data);
+
+ ret = 0;
+done:
+ rgwstore->finish_get_obj(&handle);
+ return ret;
+}
+
/**
* Save the given user information to storage.
* Returns: 0 on success, -ERR# on failure.
int rgw_get_user_info_from_index(string& key, string& bucket, RGWUserInfo& info)
{
bufferlist bl;
- int ret;
- char *data = NULL;
- struct rgw_err err;
RGWUID uid;
- void *handle = NULL;
- bufferlist::iterator iter;
- int request_len = READ_CHUNK_LEN;
- ret = rgwstore->prepare_get_obj(bucket, key, 0, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, &handle, &err);
+
+ int ret = get_obj(bucket, key, bl);
if (ret < 0)
return ret;
- do {
- ret = rgwstore->get_obj(&handle, bucket, key, &data, 0, request_len - 1);
- if (ret < 0)
- goto done;
- if (ret < request_len)
- break;
- free(data);
- request_len *= 2;
- } while (true);
-
- bl.append(data, ret);
- free(data);
-
- iter = bl.begin();
+ bufferlist::iterator iter = bl.begin();
::decode(uid, iter);
- if (!iter.end()) {
+ if (!iter.end())
info.decode(iter);
- }
- ret = 0;
-done:
- rgwstore->finish_get_obj(&handle);
- return ret;
+
+ return 0;
}
/**
return 0;
}
+
+int rgw_store_pool_info(int pool_id, RGWPoolInfo& pool_info)
+{
+ bufferlist bl;
+
+ ::encode(pool_info, bl);
+
+ string uid;
+ char buf[16];
+ snprintf(buf, sizeof(buf), "%d", pool_id);
+ string pool_id_str(buf);
+
+ int ret = put_obj(uid, pi_pool_bucket, pool_id_str, bl.c_str(), bl.length());
+ if (ret < 0) {
+ RGW_LOG(0) << "ERROR: could not write to pool=" << pi_pool_bucket << " obj=" << pool_id_str << " ret=" << ret << dendl;
+ }
+ return ret;
+}
+
+int rgw_retrieve_pool_info(int pool_id, RGWPoolInfo& pool_info)
+{
+ bufferlist bl;
+
+ string uid;
+ char buf[16];
+ snprintf(buf, sizeof(buf), "%d", pool_id);
+ string pool_id_str(buf);
+
+ int ret = get_obj(pi_pool_bucket, pool_id_str, bl);
+ if (ret < 0) {
+ RGW_LOG(0) << "ERROR: could not read from pool=" << pi_pool_bucket << " obj=" << pool_id_str << " ret=" << ret << dendl;
+ return ret;
+ }
+ bufferlist::iterator iter = bl.begin();
+ ::decode(pool_info, iter);
+
+ return 0;
+}
#define USER_INFO_UID_BUCKET_NAME ".users.uid"
#define RGW_USER_ANON_ID "anonymous"
+#define POOL_INFO_BUCKET_NAME ".pool"
+
/**
* A string wrapper that includes encode/decode functions
* for easily accessing a UID in all forms
extern int rgw_remove_email_index(string& uid, string& email);
extern int rgw_remove_openstack_name_index(string& uid, string& openstack_name);
+extern int rgw_store_pool_info(int pool_id, RGWPoolInfo& pool_info);
+extern int rgw_retrieve_pool_info(int pool_id, RGWPoolInfo& pool_info);
+
+
#endif