]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: implement s3 get bucket replication api
authorYehuda Sadeh <yehuda@redhat.com>
Thu, 28 Nov 2019 04:00:34 +0000 (20:00 -0800)
committerYehuda Sadeh <yehuda@redhat.com>
Tue, 28 Jan 2020 18:20:39 +0000 (10:20 -0800)
Signed-off-by: Yehuda Sadeh <yehuda@redhat.com>
src/rgw/rgw_op.cc
src/rgw/rgw_op.h
src/rgw/rgw_rest.h
src/rgw/rgw_rest_s3.cc
src/rgw/rgw_rest_s3.h
src/rgw/rgw_xml.h

index 207cc3e4b529828b06e56fc347dc8539731c8f26..e02e1f9d96512810cf1cf6d8528dc36197100f97 100644 (file)
@@ -1249,8 +1249,27 @@ void RGWDeleteBucketTags::execute()
   });
 }
 
+int RGWGetBucketReplication::verify_permission()
+{
+  if (!verify_bucket_permission(this, s, rgw::IAM::s3GetReplicationConfiguration)) {
+    return -EACCES;
+  }
+
+  return 0;
+}
+
+void RGWGetBucketReplication::pre_exec()
+{
+  rgw_bucket_object_pre_exec(s);
+}
+
+void RGWGetBucketReplication::execute()
+{
+  send_response_data();
+}
+
 int RGWPutBucketReplication::verify_permission() {
-  return verify_bucket_owner_or_policy(s, rgw::IAM::s3PutBucketTagging);
+  return verify_bucket_owner_or_policy(s, rgw::IAM::s3PutReplicationConfiguration);
 }
 
 void RGWPutBucketReplication::execute() {
@@ -1294,7 +1313,7 @@ void RGWDeleteBucketReplication::pre_exec()
 
 int RGWDeleteBucketReplication::verify_permission()
 {
-  return verify_bucket_owner_or_policy(s, rgw::IAM::s3PutBucketTagging);
+  return verify_bucket_owner_or_policy(s, rgw::IAM::s3DeleteReplicationConfiguration);
 }
 
 void RGWDeleteBucketReplication::execute()
index 50c9b772b24ddb7e77bfb9ee0426fbca9573a67d..e6d90341c5fdb5d0c6b1b373daa1e885fb51b92a 100644 (file)
@@ -468,6 +468,18 @@ public:
 
 struct rgw_sync_policy_group;
 
+class RGWGetBucketReplication : public RGWOp {
+public:
+  int verify_permission() override;
+  void execute() override;
+  void pre_exec() override;
+
+  virtual void send_response_data() = 0;
+  const char* name() const override { return "get_bucket_replication"; }
+  virtual uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
+  RGWOpType get_type() override { return RGW_OP_GET_BUCKET_REPLICATION; }
+};
+
 class RGWPutBucketReplication : public RGWOp {
 protected:
   bufferlist in_data;
index 1b315c7c76c4b6e9b0803c2b7180291c061b8021..ce9498453125f0604dd4d5a9243d0ec1a1b839c0 100644 (file)
@@ -194,6 +194,12 @@ public:
   virtual ~RGWPutBucketTags_ObjStore() = default; 
 };
 
+class RGWGetBucketReplication_ObjStore : public RGWGetBucketReplication {
+public:
+  RGWGetBucketReplication_ObjStore() {};
+  ~RGWGetBucketReplication_ObjStore() {};
+};
+
 class RGWPutBucketReplication_ObjStore: public RGWPutBucketReplication {
 public:
   RGWPutBucketReplication_ObjStore() = default;
index 40f2aff2b54ef75d4b11a1bd112694de5eb4f45c..c2f7c298a0171e24763be8390ae22a58b18ee320 100644 (file)
@@ -623,6 +623,10 @@ struct ReplicationConfiguration {
         RGWXMLDecoder::decode_xml("Status", status, obj);
       }
 
+      void dump_xml(Formatter *f) const {
+        encode_xml("Status", status, f);
+      }
+
       bool is_valid(CephContext *cct) const {
         bool result = is_valid_status(status);
         if (!result) {
@@ -638,6 +642,10 @@ struct ReplicationConfiguration {
       void decode_xml(XMLObj *obj) {
         RGWXMLDecoder::decode_xml("Zone", zone_names, obj);
       }
+
+      void dump_xml(Formatter *f) const {
+        encode_xml("Zone", zone_names, f);
+      }
     };
 
     struct Destination {
@@ -647,6 +655,9 @@ struct ReplicationConfiguration {
         void decode_xml(XMLObj *obj) {
           RGWXMLDecoder::decode_xml("Owner", owner, obj);
         }
+        void dump_xml(Formatter *f) const {
+          encode_xml("Owner", owner, f);
+        }
       };
 
       std::optional<AccessControlTranslation> acl_translation;
@@ -668,6 +679,14 @@ struct ReplicationConfiguration {
         }
         RGWXMLDecoder::decode_xml("Zone", zone_names, obj); /* rgw extension */
       }
+
+      void dump_xml(Formatter *f) const {
+        encode_xml("AccessControlTranslation", acl_translation, f);
+        encode_xml("Account", account, f);
+        encode_xml("Bucket", bucket, f);
+        encode_xml("StorageClass", storage_class, f);
+        encode_xml("Zone", zone_names, f);
+      }
     };
 
     struct Filter {
@@ -683,6 +702,11 @@ struct ReplicationConfiguration {
           RGWXMLDecoder::decode_xml("Key", key, obj);
           RGWXMLDecoder::decode_xml("Value", value, obj);
         };
+
+        void dump_xml(Formatter *f) const {
+          encode_xml("Key", key, f);
+          encode_xml("Value", value, f);
+        }
       };
 
       struct AndElements {
@@ -707,12 +731,21 @@ struct ReplicationConfiguration {
             }
           }
         };
+
+        void dump_xml(Formatter *f) const {
+          encode_xml("Prefix", prefix, f);
+          encode_xml("Tag", tags, f);
+        }
       };
 
       std::optional<string> prefix;
       std::optional<Tag> tag;
       std::optional<AndElements> and_elements;
 
+      bool empty() const {
+        return (!prefix && !tag && !and_elements);
+      }
+
       void decode_xml(XMLObj *obj) {
         RGWXMLDecoder::decode_xml("Prefix", prefix, obj);
         if (prefix && prefix->empty()) {
@@ -728,6 +761,12 @@ struct ReplicationConfiguration {
         }
       };
 
+      void dump_xml(Formatter *f) const {
+        encode_xml("Prefix", prefix, f);
+        encode_xml("Tag", tag, f);
+        encode_xml("And", and_elements, f);
+      }
+
       bool is_valid(CephContext *cct) const {
         if (tag && prefix) {
           ldout(cct, 5) << "NOTICE: both tag and prefix were provided in replication filter rule" << dendl;
@@ -765,6 +804,42 @@ struct ReplicationConfiguration {
         }
         return 0;
       }
+
+      void from_sync_pipe_filter(const rgw_sync_pipe_filter& f) {
+        if (f.prefix && f.tags.empty()) {
+          prefix = f.prefix;
+          return;
+        }
+        if (f.prefix) {
+          and_elements.emplace();
+          and_elements->prefix = f.prefix;
+        } else if (f.tags.size() == 1) {
+          auto iter = f.tags.begin();
+          if (iter == f.tags.end()) {
+            /* should never happen */
+            return;
+          }
+          auto& t = *iter;
+          tag.emplace();
+          tag->key = t.key;
+          tag->value = t.value;
+          return;
+        }
+
+        if (f.tags.empty()) {
+          return;
+        }
+
+        if (!and_elements) {
+          and_elements.emplace();
+        }
+
+        for (auto& t : f.tags) {
+          auto& tag = and_elements->tags.emplace_back();
+          tag.key = t.key;
+          tag.value = t.value;
+        }
+      }
     };
 
     set<rgw_zone_id> get_zone_ids_from_names(rgw::sal::RGWRadosStore *store,
@@ -781,6 +856,20 @@ struct ReplicationConfiguration {
       return std::move(ids);
     }
 
+    vector<string> get_zone_names_from_ids(rgw::sal::RGWRadosStore *store,
+                                           const set<rgw_zone_id>& zone_ids) const {
+      vector<string> names;
+
+      for (auto& id : zone_ids) {
+        RGWZone *zone;
+        if (store->svc()->zone->find_zone(id, &zone)) {
+          names.emplace_back(zone->name);
+        }
+      }
+
+      return std::move(names);
+    }
+
     std::optional<DeleteMarkerReplication> delete_marker_replication;
     std::optional<Source> source;
     Destination destination;
@@ -805,6 +894,9 @@ struct ReplicationConfiguration {
       if (!filter) {
         RGWXMLDecoder::decode_xml("Filter", filter, obj);
       } else {
+        /* don't want to have filter reset because it might have been initialized
+         * when decoding prefix
+         */
         RGWXMLDecoder::decode_xml("Filter", *filter, obj);
       }
 
@@ -812,6 +904,16 @@ struct ReplicationConfiguration {
       RGWXMLDecoder::decode_xml("Status", status, obj);
     }
 
+    void dump_xml(Formatter *f) const {
+      encode_xml("DeleteMarkerReplication", delete_marker_replication, f);
+      encode_xml("Source", source, f);
+      encode_xml("Destination", destination, f);
+      encode_xml("Filter", filter, f);
+      encode_xml("ID", id, f);
+      encode_xml("Priority", priority, f);
+      encode_xml("Status", status, f);
+    }
+
     bool is_valid(CephContext *cct) const {
       if (!is_valid_status(status)) {
         ldout(cct, 5) << "NOTICE: bad status provided in rule (status=" << status << ")" << dendl;
@@ -874,6 +976,46 @@ struct ReplicationConfiguration {
 
       return 0;
     }
+
+    void from_sync_policy_pipe(rgw::sal::RGWRadosStore *store,
+                              const rgw_sync_bucket_pipes& pipe,
+                              bool enabled) {
+      id = pipe.id;
+      status = (enabled ? "Enabled" : "Disabled");
+      priority = pipe.params.priority;
+
+      if (pipe.source.all_zones) {
+        source.reset();
+      } else if (pipe.source.zones) {
+        source.emplace();
+        source->zone_names = get_zone_names_from_ids(store, *pipe.source.zones);
+      }
+
+      if (!pipe.dest.all_zones &&
+          pipe.dest.zones) {
+        destination.zone_names = get_zone_names_from_ids(store, *pipe.dest.zones);
+      }
+
+      if (pipe.params.dest.acl_translation) {
+        destination.acl_translation.emplace();
+        destination.acl_translation->owner = pipe.params.dest.acl_translation->owner.to_str();
+      }
+
+      if (pipe.params.dest.storage_class) {
+        destination.storage_class = *pipe.params.dest.storage_class;
+      }
+
+      if (pipe.dest.bucket) {
+        destination.bucket = pipe.dest.bucket->get_key();
+      }
+
+      filter.emplace();
+      filter->from_sync_pipe_filter(pipe.params.source.filter);
+
+      if (filter->empty()) {
+        filter.reset();
+      }
+    }
   };
 
   std::vector<Rule> rules;
@@ -883,6 +1025,11 @@ struct ReplicationConfiguration {
     RGWXMLDecoder::decode_xml("Rule", rules, obj);
   }
 
+  void dump_xml(Formatter *f) const {
+    encode_xml("Role", role, f);
+    encode_xml("Rule", rules, f);
+  }
+
   int to_sync_policy_groups(req_state *s, rgw::sal::RGWRadosStore *store,
                             vector<rgw_sync_policy_group> *result) const {
     result->resize(2);
@@ -912,10 +1059,52 @@ struct ReplicationConfiguration {
     }
     return 0;
   }
+
+  void from_sync_policy_group(rgw::sal::RGWRadosStore *store,
+                              const rgw_sync_policy_group& group) {
+
+    bool enabled = (group.status == rgw_sync_policy_group::Status::ENABLED);
+
+    for (auto& pipe : group.pipes) {
+      auto& rule = rules.emplace_back();
+      rule.from_sync_policy_pipe(store, pipe, enabled);
+    }
+  }
 };
 
 }
 
+void RGWGetBucketReplication_ObjStore_S3::send_response_data()
+{
+  if (op_ret)
+    set_req_state_err(s, op_ret);
+  dump_errno(s);
+  end_header(s, this, "application/xml");
+  dump_start(s);
+
+  ReplicationConfiguration conf;
+
+  if (s->bucket_info.sync_policy) {
+    auto policy = s->bucket_info.sync_policy;
+
+    auto iter = policy->groups.find(enabled_group_id);
+    if (iter != policy->groups.end()) {
+      conf.from_sync_policy_group(store, iter->second);
+    }
+    iter = policy->groups.find(disabled_group_id);
+    if (iter != policy->groups.end()) {
+      conf.from_sync_policy_group(store, iter->second);
+    }
+  }
+
+  if (!op_ret) {
+  s->formatter->open_object_section_in_ns("ReplicationConfiguration", XMLNS_AWS_S3);
+  conf.dump_xml(s->formatter);
+  s->formatter->close_section();
+  rgw_flush_formatter_and_reset(s, s->formatter);
+  }
+}
+
 int RGWPutBucketReplication_ObjStore_S3::get_params()
 {
   RGWXMLParser parser;
@@ -4087,7 +4276,7 @@ RGWOp *RGWHandler_REST_Bucket_S3::op_get()
   } else if (is_notification_op()) {
     return RGWHandler_REST_PSNotifs_S3::create_get_op();
   } else if (is_replication_op()) {
-    return nullptr; // new RGWGetBucketReplication_ObjStore_S3;
+    return new RGWGetBucketReplication_ObjStore_S3;
   }
   return get_obj_op(true);
 }
index a301f24e1fd6e3204d013803ff9e6aa5b23927d1..513be8a0ebc2a5d545870b2eeea314ecf5f52f46 100644 (file)
@@ -101,6 +101,12 @@ public:
   void send_response() override;
 };
 
+class RGWGetBucketReplication_ObjStore_S3 : public RGWGetBucketReplication_ObjStore
+{
+public:
+  void send_response_data() override;
+};
+
 class RGWPutBucketReplication_ObjStore_S3 : public RGWPutBucketReplication_ObjStore
 {
 public:
index 7712572d6f8af5a6aa1d7fa1090ff277f447c3c3..b3e1e8ee681fc671dfbd79c013e556754d753848 100644 (file)
@@ -353,6 +353,23 @@ static void do_encode_xml(const char *name, const std::list<T>& l, const char *e
   f->close_section();
 }
 
+template<class T>
+static void encode_xml(const char *name, const std::vector<T>& l, ceph::Formatter *f)
+{
+  for (typename std::vector<T>::const_iterator iter = l.begin(); iter != l.end(); ++iter) {
+    encode_xml(name, *iter, f);
+  }
+}
+
+template<class T>
+static void encode_xml(const char *name, const std::optional<T>& o, ceph::Formatter *f)
+{
+  if (!o) {
+    return;
+  }
+
+  encode_xml(name, *o, f);
+}
 
 
 #endif