]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: work on REST handler for es module
authorYehuda Sadeh <yehuda@redhat.com>
Tue, 21 Mar 2017 02:07:21 +0000 (19:07 -0700)
committerYehuda Sadeh <yehuda@redhat.com>
Tue, 30 May 2017 20:24:39 +0000 (13:24 -0700)
Signed-off-by: Yehuda Sadeh <yehuda@redhat.com>
13 files changed:
src/rgw/CMakeLists.txt
src/rgw/rgw_common.h
src/rgw/rgw_es_query.cc
src/rgw/rgw_es_query.h [new file with mode: 0644]
src/rgw/rgw_main.cc
src/rgw/rgw_op.cc
src/rgw/rgw_op.h
src/rgw/rgw_rest_s3.cc
src/rgw/rgw_sync_module.h
src/rgw/rgw_sync_module_es.cc
src/rgw/rgw_sync_module_es.h
src/rgw/rgw_sync_module_es_rest.cc [new file with mode: 0644]
src/rgw/rgw_sync_module_es_rest.h [new file with mode: 0644]

index fc7aa1ee45169004abd8261b59f600b53bbc5b54..3fa36995666438f1460f6ca2eed3a771dabf0c81 100644 (file)
@@ -73,6 +73,7 @@ set(rgw_a_srcs
   rgw_data_sync.cc
   rgw_sync_module.cc
   rgw_sync_module_es.cc
+  rgw_sync_module_es_rest.cc
   rgw_sync_module_log.cc
   rgw_period_history.cc
   rgw_period_puller.cc
index bc049346e7322534d544512a6eb06b2941836d6b..529dfebe09846ec74166b85207d54056788c8026 100644 (file)
@@ -464,8 +464,8 @@ enum RGWOpType {
   /* rgw specific */
   RGW_OP_ADMIN_SET_METADATA,
   RGW_OP_GET_OBJ_LAYOUT,
-
-  RGW_OP_BULK_UPLOAD
+  RGW_OP_BULK_UPLOAD,
+  RGW_OP_METADATA_SEARCH,
 };
 
 class RGWAccessControlPolicy;
index fc35786dfa4ef3a0be8da93e845c38dbe621b37c..e89d261d1d67a914ae0027e29c893609b29bb6da 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "common/ceph_json.h"
 #include "rgw_common.h"
+#include "rgw_es_query.h"
 
 using namespace std;
 
@@ -105,44 +106,6 @@ static bool infix_to_prefix(list<string>& source, list<string> *out)
   return true;
 }
 
-class ESQueryStack {
-  list<string> l;
-  list<string>::iterator iter;
-
-public:
-  ESQueryStack(list<string>& src) {
-    assign(src);
-  }
-
-  ESQueryStack() {}
-
-  void assign(list<string>& src) {
-    l.swap(src);
-    iter = l.begin();
-  }
-
-  bool peek(string *dest) {
-    if (done()) {
-      return false;
-    }
-    *dest = *iter;
-    return true;
-  }
-
-  bool pop(string *dest) {
-    bool valid = peek(dest);
-    if (!valid) {
-      return false;
-    }
-    ++iter;
-    return true;
-  }
-
-  bool done() {
-    return (iter == l.end());
-  }
-};
-
 class ESQueryNode {
 public:
   ESQueryNode() {}
@@ -375,158 +338,140 @@ static bool is_val_char(char c)
   return (c != ')');
 }
 
-class ESInfixQueryParser {
-  string query;
-  int size;
-  const char *str;
-  int pos{0};
-  list<string> args;
-
-  void skip_whitespace(const char *str, int size, int& pos) {
-    while (pos < size && isspace(str[pos])) {
-      ++pos;
-    }
+void ESInfixQueryParser::skip_whitespace(const char *str, int size, int& pos) {
+  while (pos < size && isspace(str[pos])) {
+    ++pos;
   }
+}
 
-  bool get_next_token(bool (*filter)(char)) {
-    skip_whitespace(str, size, pos);
-    int token_start = pos;
-    while (pos < size && filter(str[pos])) {
-      ++pos;
-    }
-    if (pos == token_start) {
-      return false;
-    }
-    string token = string(str + token_start, pos - token_start);
-    args.push_back(token);
-    return true;
+bool ESInfixQueryParser::get_next_token(bool (*filter)(char)) {
+  skip_whitespace(str, size, pos);
+  int token_start = pos;
+  while (pos < size && filter(str[pos])) {
+    ++pos;
   }
-
-  bool parse_condition() {
-    /*
-     * condition: <key> <operator> <val>
-     *
-     * whereas key: needs to conform to http header field restrictions
-     *         operator: one of the following: < <= == >= >
-     *         val: ascii, terminated by either space or ')' (or end of string)
-     */
-
-    /* parse key */
-    bool valid = get_next_token(is_key_char) &&
-      get_next_token(is_op_char) &&
-      get_next_token(is_val_char);
-
-    if (!valid) {
-      return false;
-    }
-
-    return true;
+  if (pos == token_start) {
+    return false;
   }
+  string token = string(str + token_start, pos - token_start);
+  args.push_back(token);
+  return true;
+}
 
-  bool parse_and_or() {
-    skip_whitespace(str, size, pos);
-    if (pos + 3 <= size && strncmp(str + pos, "and", 3) == 0) {
-      pos += 3;
-      args.push_back("and");
-      return true;
-    }
+bool ESInfixQueryParser::parse_condition() {
+  /*
+   * condition: <key> <operator> <val>
+   *
+   * whereas key: needs to conform to http header field restrictions
+   *         operator: one of the following: < <= == >= >
+   *         val: ascii, terminated by either space or ')' (or end of string)
+   */
 
-    if (pos + 2 <= size && strncmp(str + pos, "or", 2) == 0) {
-      pos += 2;
-      args.push_back("or");
-      return true;
-    }
+  /* parse key */
+  bool valid = get_next_token(is_key_char) &&
+    get_next_token(is_op_char) &&
+    get_next_token(is_val_char);
 
+  if (!valid) {
     return false;
   }
 
-  bool parse_specific_char(const char *pchar) {
-    skip_whitespace(str, size, pos);
-    if (pos >= size) {
-      return false;
-    }
-    if (str[pos] != *pchar) {
-      return false;
-    }
+  return true;
+}
 
-    args.push_back(pchar);
-    ++pos;
+bool ESInfixQueryParser::parse_and_or() {
+  skip_whitespace(str, size, pos);
+  if (pos + 3 <= size && strncmp(str + pos, "and", 3) == 0) {
+    pos += 3;
+    args.push_back("and");
     return true;
   }
 
-  bool parse_open_bracket() {
-    return parse_specific_char("(");
+  if (pos + 2 <= size && strncmp(str + pos, "or", 2) == 0) {
+    pos += 2;
+    args.push_back("or");
+    return true;
   }
 
-  bool parse_close_bracket() {
-    return parse_specific_char(")");
+  return false;
+}
+
+bool ESInfixQueryParser::parse_specific_char(const char *pchar) {
+  skip_whitespace(str, size, pos);
+  if (pos >= size) {
+    return false;
+  }
+  if (str[pos] != *pchar) {
+    return false;
   }
 
-public:
-  ESInfixQueryParser(const string& _query) : query(_query), size(query.size()), str(query.c_str()) {}
-  bool parse(list<string> *result) {
-    /*
-     * expression: [(]<condition>[[and/or]<condition>][)][and/or]...
-     */
-
-    while (pos < size) {
-      parse_open_bracket();
-      if (!parse_condition()) {
-        return false;
-      }
-      parse_close_bracket();
-      parse_and_or();
-    }
+  args.push_back(pchar);
+  ++pos;
+  return true;
+}
 
-    result->swap(args);
+bool ESInfixQueryParser::parse_open_bracket() {
+  return parse_specific_char("(");
+}
 
-    return true;
-  }
-};
+bool ESInfixQueryParser::parse_close_bracket() {
+  return parse_specific_char(")");
+}
 
-class ESQueryCompiler {
-  ESInfixQueryParser parser;
-  ESQueryStack stack;
-  ESQueryNode *query_root{nullptr};
+bool ESInfixQueryParser::parse(list<string> *result) {
+  /*
+   * expression: [(]<condition>[[and/or]<condition>][)][and/or]...
+   */
 
-  bool convert(list<string>& infix) {
-    list<string> prefix;
-    if (!infix_to_prefix(infix, &prefix)) {
-      return false;
-    }
-    stack.assign(prefix);
-    if (!alloc_node(&stack, &query_root)) {
+  while (pos < size) {
+    parse_open_bracket();
+    if (!parse_condition()) {
       return false;
     }
-    if (!stack.done()) {
-      return false;
-    }
-    return true;
+    parse_close_bracket();
+    parse_and_or();
   }
 
-public:
-  ESQueryCompiler(const string& query) : parser(query) {}
-  ~ESQueryCompiler() {
-    delete query_root;
-  }
+  result->swap(args);
 
-  bool compile() {
-    list<string> infix;
-    if (!parser.parse(&infix)) {
-      return false;
-    }
+  return true;
+}
 
-    if (!convert(infix)) {
-      return false;
-    }
+bool ESQueryCompiler::convert(list<string>& infix) {
+  list<string> prefix;
+  if (!infix_to_prefix(infix, &prefix)) {
+    return false;
+  }
+  stack.assign(prefix);
+  if (!alloc_node(&stack, &query_root)) {
+    return false;
+  }
+  if (!stack.done()) {
+    return false;
+  }
+  return true;
+}
 
-    return true;
+ESQueryCompiler::~ESQueryCompiler() {
+  delete query_root;
+}
+
+bool ESQueryCompiler::compile() {
+  list<string> infix;
+  if (!parser.parse(&infix)) {
+    return false;
   }
 
-  void dump(Formatter *f) const {
-    encode_json("query", *query_root, f);
+  if (!convert(infix)) {
+    return false;
   }
-};
+
+  return true;
+}
+
+void ESQueryCompiler::dump(Formatter *f) const {
+  encode_json("query", *query_root, f);
+}
 
 
 int main(int argc, char *argv[])
diff --git a/src/rgw/rgw_es_query.h b/src/rgw/rgw_es_query.h
new file mode 100644 (file)
index 0000000..c8b8375
--- /dev/null
@@ -0,0 +1,81 @@
+#ifndef CEPH_RGW_ES_QUERY_H
+#define CEPH_RGW_ES_QUERY_H
+
+class ESQueryStack {
+  list<string> l;
+  list<string>::iterator iter;
+
+public:
+  ESQueryStack(list<string>& src) {
+    assign(src);
+  }
+
+  ESQueryStack() {}
+
+  void assign(list<string>& src) {
+    l.swap(src);
+    iter = l.begin();
+  }
+
+  bool peek(string *dest) {
+    if (done()) {
+      return false;
+    }
+    *dest = *iter;
+    return true;
+  }
+
+  bool pop(string *dest) {
+    bool valid = peek(dest);
+    if (!valid) {
+      return false;
+    }
+    ++iter;
+    return true;
+  }
+
+  bool done() {
+    return (iter == l.end());
+  }
+};
+
+class ESInfixQueryParser {
+  string query;
+  int size;
+  const char *str;
+  int pos{0};
+  list<string> args;
+
+  void skip_whitespace(const char *str, int size, int& pos);
+  bool get_next_token(bool (*filter)(char));
+
+  bool parse_condition();
+  bool parse_and_or();
+  bool parse_specific_char(const char *pchar);
+  bool parse_open_bracket();
+  bool parse_close_bracket();
+
+public:
+  ESInfixQueryParser(const string& _query) : query(_query), size(query.size()), str(query.c_str()) {}
+  bool parse(list<string> *result);
+};
+
+class ESQueryNode;
+
+class ESQueryCompiler {
+  ESInfixQueryParser parser;
+  ESQueryStack stack;
+  ESQueryNode *query_root{nullptr};
+
+  bool convert(list<string>& infix);
+
+public:
+  ESQueryCompiler(const string& query) : parser(query) {}
+  ~ESQueryCompiler();
+
+  bool compile();
+  void dump(Formatter *f) const;
+};
+
+
+#endif
index f018faba8d62a1a7913941a05fb1cdd708f61258..5c3dbb0582b6beb3e9fddd694d1166763ea7250c 100644 (file)
@@ -182,6 +182,12 @@ static RGWRESTMgr *set_logging(RGWRESTMgr *mgr)
   return mgr;
 }
 
+static RGWRESTMgr *rest_filter(RGWRados *store, int dialect, RGWRESTMgr *orig)
+{
+  RGWSyncModuleInstanceRef sync_module = store->get_sync_module();
+  return sync_module->get_rest_filter(dialect, orig);
+}
+
 RGWRealmReloader *preloader = NULL;
 
 static void reloader_handler(int signum)
@@ -377,7 +383,8 @@ int main(int argc, const char **argv)
   const bool swift_at_root = g_conf->rgw_swift_url_prefix == "/";
   if (apis_map.count("s3") > 0 || s3website_enabled) {
     if (! swift_at_root) {
-      rest.register_default_mgr(set_logging(new RGWRESTMgr_S3(s3website_enabled)));
+      rest.register_default_mgr(set_logging(rest_filter(store, RGW_REST_S3,
+                                                        new RGWRESTMgr_S3(s3website_enabled))));
     } else {
       derr << "Cannot have the S3 or S3 Website enabled together with "
            << "Swift API placed in the root of hierarchy" << dendl;
@@ -401,7 +408,8 @@ int main(int argc, const char **argv)
 
     if (! swift_at_root) {
       rest.register_resource(g_conf->rgw_swift_url_prefix,
-                          set_logging(swift_resource));
+                          set_logging(rest_filter(store, RGW_REST_SWIFT,
+                                                  swift_resource)));
     } else {
       if (store->get_zonegroup().zones.size() > 1) {
         derr << "Placing Swift API in the root of URL hierarchy while running"
index ac025c6e7d93b80ca71ed38e37951f7b71d2ff9e..6caa57c067433320cc1b63925d99f53dd7286801 100644 (file)
@@ -631,7 +631,7 @@ rgw::IAM::Environment rgw_build_iam_environment(RGWRados* store,
   return e;
 }
 
-static void rgw_bucket_object_pre_exec(struct req_state *s)
+void rgw_bucket_object_pre_exec(struct req_state *s)
 {
   if (s->expect_cont)
     dump_continue(s);
index 1b4f02f1b7f59a770dcee5c25fb0e7ace83074f2..ed7812cf80b5679122f746b99e594a3f713b814d 100644 (file)
@@ -97,6 +97,9 @@ public:
 };
 
 
+
+void rgw_bucket_object_pre_exec(struct req_state *s);
+
 /**
  * Provide the base class for all ops.
  */
index 7174a0a4e2028708f068860e8ff4f72253b025f5..c8a3f8371fa8e31ed95a64fdccc1602d5da94965 100644 (file)
@@ -2756,10 +2756,11 @@ RGWOp *RGWHandler_REST_Service_S3::op_post()
 RGWOp *RGWHandler_REST_Bucket_S3::get_obj_op(bool get_data)
 {
   // Non-website mode
-  if (get_data)
+  if (get_data) {
     return new RGWListBucket_ObjStore_S3;
-  else
+  } else {
     return new RGWStatBucket_ObjStore_S3;
+  }
 }
 
 RGWOp *RGWHandler_REST_Bucket_S3::op_get()
index 07b30a0201bf65b84b467b456036a4bc3519eb1d..55b39b775e111f487af95d29fee7d21cff820ad6 100644 (file)
@@ -27,11 +27,16 @@ public:
                                              rgw_bucket_entry_owner& owner, bool versioned, uint64_t versioned_epoch, rgw_zone_set *zones_trace) = 0;
 };
 
+class RGWRESTMgr;
+
 class RGWSyncModuleInstance {
 public:
   RGWSyncModuleInstance() {}
   virtual ~RGWSyncModuleInstance() {}
   virtual RGWDataSyncModule *get_data_handler() = 0;
+  virtual RGWRESTMgr *get_rest_filter(int dialect, RGWRESTMgr *orig) {
+    return orig;
+  }
 };
 
 typedef std::shared_ptr<RGWSyncModuleInstance> RGWSyncModuleInstanceRef;
index f04e26c9144a91a676c6f0596c444d31a5bb2ab4..7c2ff99731ec1e0e411f84cc65d499d56105922e 100644 (file)
@@ -4,8 +4,10 @@
 #include "rgw_data_sync.h"
 #include "rgw_boost_asio_yield.h"
 #include "rgw_sync_module_es.h"
+#include "rgw_sync_module_es_rest.h"
 #include "rgw_rest_conn.h"
 #include "rgw_cr_rest.h"
+#include "rgw_op.h"
 
 #define dout_subsys ceph_subsys_rgw
 
@@ -311,16 +313,32 @@ public:
                             << " versioned=" << versioned << " versioned_epoch=" << versioned_epoch << dendl;
     return NULL;
   }
+  RGWRESTConn *get_rest_conn() {
+    return conf.conn;
+  }
 };
 
-class RGWElasticSyncModuleInstance : public RGWSyncModuleInstance {
-  RGWElasticDataSyncModule data_handler;
-public:
-  RGWElasticSyncModuleInstance(CephContext *cct, const string& endpoint) : data_handler(cct, endpoint) {}
-  RGWDataSyncModule *get_data_handler() override {
-    return &data_handler;
+RGWElasticSyncModuleInstance::RGWElasticSyncModuleInstance(CephContext *cct, const string& endpoint)
+{
+  data_handler = std::unique_ptr<RGWElasticDataSyncModule>(new RGWElasticDataSyncModule(cct, endpoint));
+}
+
+RGWDataSyncModule *RGWElasticSyncModuleInstance::get_data_handler()
+{
+  return data_handler.get();
+}
+
+RGWRESTConn *RGWElasticSyncModuleInstance::get_rest_conn()
+{
+  return data_handler->get_rest_conn();
+}
+
+RGWRESTMgr *RGWElasticSyncModuleInstance::get_rest_filter(int dialect, RGWRESTMgr *orig) {
+  if (dialect != RGW_REST_S3) {
+    return orig;
   }
-};
+  return new RGWRESTMgr_MDSearch_S3(this);
+}
 
 int RGWElasticSyncModule::create_instance(CephContext *cct, map<string, string>& config, RGWSyncModuleInstanceRef *instance) {
   string endpoint;
index 73c8368571d8d52d5a86a2e876dbeeab937718cd..28b11716fd0cdfaea4121232d777859a16da4b8d 100644 (file)
@@ -12,4 +12,16 @@ public:
   int create_instance(CephContext *cct, map<string, string>& config, RGWSyncModuleInstanceRef *instance) override;
 };
 
+class RGWElasticDataSyncModule;
+class RGWRESTConn;
+
+class RGWElasticSyncModuleInstance : public RGWSyncModuleInstance {
+  std::unique_ptr<RGWElasticDataSyncModule> data_handler;
+public:
+  RGWElasticSyncModuleInstance(CephContext *cct, const string& endpoint);
+  RGWDataSyncModule *get_data_handler() override;
+  RGWRESTMgr *get_rest_filter(int dialect, RGWRESTMgr *orig) override;
+  RGWRESTConn *get_rest_conn();
+};
+
 #endif
diff --git a/src/rgw/rgw_sync_module_es_rest.cc b/src/rgw/rgw_sync_module_es_rest.cc
new file mode 100644 (file)
index 0000000..f0c9d30
--- /dev/null
@@ -0,0 +1,118 @@
+#include "rgw_sync_module_es.h"
+#include "rgw_sync_module_es_rest.h"
+#include "rgw_es_query.h"
+#include "rgw_op.h"
+#include "rgw_rest.h"
+#include "rgw_rest_s3.h"
+
+#define dout_context g_ceph_context
+#define dout_subsys ceph_subsys_rgw
+
+class RGWMetadataSearch : public RGWOp {
+protected:
+  string expression;
+
+public:
+  RGWMetadataSearch() {}
+
+  int verify_permission() {
+    return 0;
+  }
+  virtual int get_params() = 0;
+  void pre_exec();
+  void execute();
+
+  virtual void send_response() = 0;
+  virtual const string name() { return "metadata_search"; }
+  virtual RGWOpType get_type() { return RGW_OP_METADATA_SEARCH; }
+  virtual uint32_t op_mask() { return RGW_OP_TYPE_READ; }
+};
+
+void RGWMetadataSearch::pre_exec()
+{
+  rgw_bucket_object_pre_exec(s);
+}
+
+
+void RGWMetadataSearch::execute()
+{
+  op_ret = get_params();
+  if (op_ret < 0)
+    return;
+
+  ESQueryCompiler es_query(expression);
+  
+  bool valid = es_query.compile();
+  if (!valid) {
+    ldout(s->cct, 10) << "invalid query, failed generating request json" << dendl;
+    op_ret = -EINVAL;
+    return;
+  }
+
+}
+
+class RGWMetadataSearch_ObjStore_S3 : public RGWMetadataSearch {
+public:
+  RGWMetadataSearch_ObjStore_S3() {}
+
+  int get_params() override {
+    expression = s->info.args.get("query");
+    return 0;
+  }
+  void send_response() override {
+    if (op_ret)
+      set_req_state_err(s, op_ret);
+    dump_errno(s);
+    end_header(s, this, "application/xml");
+
+    if (op_ret < 0) {
+      return;
+    }
+
+    // TODO
+
+  }
+};
+
+class RGWHandler_REST_MDSearch_S3 : public RGWHandler_REST_S3 {
+protected:
+  RGWOp *op_get() {
+    if (!s->info.args.exists("query")) {
+      return nullptr;
+    }
+    return new RGWMetadataSearch_ObjStore_S3;
+  }
+  RGWOp *op_head() {
+    return nullptr;
+  }
+  RGWOp *op_post() {
+    return nullptr;
+  }
+public:
+  RGWHandler_REST_MDSearch_S3() {}
+  virtual ~RGWHandler_REST_MDSearch_S3() {}
+};
+
+
+RGWHandler_REST* RGWRESTMgr_MDSearch_S3::get_handler(struct req_state* const s,
+                                                     const rgw::auth::StrategyRegistry& auth_registry,
+                                                     const std::string& frontend_prefix)
+{
+  int ret =
+    RGWHandler_REST_S3::init_from_header(s,
+                                       RGW_FORMAT_XML, true);
+  if (ret < 0) {
+    return nullptr;
+  }
+
+  if (!s->object.empty()) {
+    return nullptr;
+  }
+
+  RGWHandler_REST *handler = new RGWHandler_REST_MDSearch_S3;
+
+  ldout(s->cct, 20) << __func__ << " handler=" << typeid(*handler).name()
+                   << dendl;
+  return handler;
+}
+
diff --git a/src/rgw/rgw_sync_module_es_rest.h b/src/rgw/rgw_sync_module_es_rest.h
new file mode 100644 (file)
index 0000000..7578b81
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef CEPH_RGW_SYNC_MODULE_ES_REST_H
+#define CEPH_RGW_SYNC_MODULE_ES_REST_H
+
+#include "rgw_rest.h"
+
+class RGWElasticSyncModuleInstance;
+
+class RGWRESTMgr_MDSearch_S3 : public RGWRESTMgr {
+  RGWElasticSyncModuleInstance *es_module;
+public:
+  explicit RGWRESTMgr_MDSearch_S3(RGWElasticSyncModuleInstance *_es_module) : es_module(_es_module) {}
+
+  RGWHandler_REST *get_handler(struct req_state* s,
+                               const rgw::auth::StrategyRegistry& auth_registry,
+                               const std::string& frontend_prefix) override;
+};
+
+#endif