]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: support object transition in lifecycle config set.
authorZhang Shaowen <zhangshaowen@cmss.chinamobile.com>
Mon, 23 Jul 2018 09:43:18 +0000 (17:43 +0800)
committerYehuda Sadeh <yehuda@redhat.com>
Fri, 4 Jan 2019 03:00:22 +0000 (19:00 -0800)
Signed-off-by: Zhang Shaowen <zhangshaowen@cmss.chinamobile.com>
src/rgw/rgw_lc.cc
src/rgw/rgw_lc.h
src/rgw/rgw_lc_s3.cc
src/rgw/rgw_lc_s3.h

index fe056655e2a3593f4017542c35373d1199602106..e6ab1d8d5b7f99cddbb45ec506ca20a576e1a2ff 100644 (file)
@@ -36,12 +36,33 @@ bool LCRule::valid()
   if (id.length() > MAX_ID_LEN) {
     return false;
   }
-  else if(expiration.empty() && noncur_expiration.empty() && mp_expiration.empty() && !dm_expiration) {
+  else if(expiration.empty() && noncur_expiration.empty() && mp_expiration.empty() && !dm_expiration &&
+          transitions.empty() && noncur_transitions.empty()) {
     return false;
   }
   else if (!expiration.valid() || !noncur_expiration.valid() || !mp_expiration.valid()) {
     return false;
   }
+  if (!transitions.empty()) {
+    bool using_days = expiration.has_days();
+    bool using_date = expiration.has_date();
+    for (const auto& elem : transitions) {
+      if (!elem.second.valid()) {
+        return false;
+      }
+      using_days = using_days || elem.second.has_days();
+      using_date = using_date || elem.second.has_date();
+      if (using_days && using_date) {
+        return false;
+      }
+    }
+  }
+  for (const auto& elem : noncur_transitions) {
+    if (!elem.second.valid()) {
+      return false;
+    }
+  }
+
   return true;
 }
 
@@ -79,7 +100,23 @@ bool RGWLifecycleConfiguration::_add_rule(LCRule *rule)
     op.mp_expiration = rule->get_mp_expiration().get_days();
   }
   op.dm_expiration = rule->get_dm_expiration();
-
+  for (const auto &elem : rule->get_transitions()) {
+    transition_action action;
+    if (elem.second.has_days()) {
+      action.days = elem.second.get_days();
+    } else {
+      action.date = ceph::from_iso_8601(elem.second.get_date());
+    }
+    action.storage_class = elem.first;
+    op.transitions.emplace(action.storage_class, std::move(action));
+  }
+  for (const auto &elem : rule->get_noncur_transitions()) {
+    transition_action action;
+    action.days = elem.second.get_days();
+    action.date = ceph::from_iso_8601(elem.second.get_date());
+    action.storage_class = elem.first;
+    op.noncur_transitions.emplace(action.storage_class, std::move(action));
+  }
   std::string prefix;
   if (rule->get_filter().has_prefix()){
     prefix = rule->get_filter().get_prefix();
@@ -120,9 +157,20 @@ bool RGWLifecycleConfiguration::has_same_action(const lc_op& first, const lc_op&
     return true;
   } else if (first.mp_expiration > 0 && second.mp_expiration > 0) {
     return true;
-  } else {
-    return false;
+  } else if (!first.transitions.empty() && !second.transitions.empty()) {
+    for (auto &elem : first.transitions) {
+      if (second.transitions.find(elem.first) != second.transitions.end()) {
+        return true;
+      }
+    }
+  } else if (!first.noncur_transitions.empty() && !second.noncur_transitions.empty()) {
+    for (auto &elem : first.noncur_transitions) {
+      if (second.noncur_transitions.find(elem.first) != second.noncur_transitions.end()) {
+        return true;
+      }
+    }
   }
+  return false;
 }
 
 //Rules are conflicted: if one rule's prefix starts with other rule's prefix, and these two rules
index 687b9aaa9241607adcff62a6c4235c12dc2df1d7..04c5dff8c4b8cb418ea4b6493809f6cabb67e30b 100644 (file)
@@ -38,6 +38,13 @@ typedef enum {
   lc_complete,
 }LC_BUCKET_STATUS;
 
+typedef enum {
+  standard_ia = 0,
+  onezone_ia,
+  glacier,
+  undefined,
+} STORAGE_CLASS;
+
 class LCExpiration
 {
 protected:
@@ -92,7 +99,80 @@ public:
     return true;
   }
 };
-WRITE_CLASS_ENCODER(LCExpiration)
+WRITE_CLASS_ENCODER(LCExpiration);
+
+class LCTransition
+{
+protected:
+  string days;
+  string date;
+  string storage_class;
+
+public:
+  int get_days() const {
+    return atoi(days.c_str());
+  }
+
+  string get_date() const {
+    return date;
+  }
+
+  string get_storage_class_str() const {
+    return storage_class;
+  }
+
+  STORAGE_CLASS get_storage_class() const {
+    if (storage_class.compare("STANDARD_IA") == 0) {
+      return standard_ia;
+    } else if (storage_class.compare("ONEZONE_IA") == 0) {
+      return onezone_ia;
+    } else if (storage_class.compare("GLACIER") == 0) {
+      return glacier;
+    } else {
+      return undefined;
+    }
+  }
+
+  bool has_days() const {
+    return !days.empty();
+  }
+
+  bool has_date() const {
+    return !date.empty();
+  }
+
+  bool empty() const {
+    return days.empty() && date.empty();
+  }
+
+  bool valid() const {
+    if (!days.empty() && !date.empty()) {
+      return false;
+    } else if (!days.empty() && get_days() <=0) {
+      return false;
+    }
+    //We've checked date in xml parsing
+    return true;
+  }
+
+  void encode(bufferlist& bl) const {
+    ENCODE_START(1, 1, bl);
+    encode(days, bl);
+    encode(date, bl);
+    encode(storage_class, bl);
+    ENCODE_FINISH(bl);
+  }
+
+  void decode(bufferlist::const_iterator& bl) {
+    DECODE_START(1, bl);
+    decode(days, bl);
+    decode(date, bl);
+    decode(storage_class, bl);
+    DECODE_FINISH(bl);
+  }
+  void dump(Formatter *f) const;
+};
+WRITE_CLASS_ENCODER(LCTransition);
 
 class LCFilter
 {
@@ -162,6 +242,8 @@ protected:
   LCExpiration noncur_expiration;
   LCExpiration mp_expiration;
   LCFilter filter;
+  map<int, LCTransition> transitions;
+  map<int, LCTransition> noncur_transitions;
   bool dm_expiration = false;
 
 public:
@@ -210,6 +292,14 @@ public:
     return dm_expiration;
   }
 
+  map<int, LCTransition>& get_transitions() {
+    return transitions;
+  }
+
+  map<int, LCTransition>& get_noncur_transitions() {
+    return noncur_transitions;
+  }
+
   void set_id(const string& _id) {
     id = _id;
   }
@@ -238,10 +328,20 @@ public:
     dm_expiration = _dm_expiration;
   }
 
+  bool add_transition(LCTransition* _transition) {
+    auto ret = transitions.emplace(_transition->get_storage_class(), *_transition);
+    return ret.second;
+  }
+
+  bool add_noncur_transition(LCTransition* _noncur_transition) {
+    auto ret = noncur_transitions.emplace(_noncur_transition->get_storage_class(), *_noncur_transition);
+    return ret.second;
+  }
+
   bool valid();
   
   void encode(bufferlist& bl) const {
-     ENCODE_START(5, 1, bl);
+     ENCODE_START(6, 1, bl);
      encode(id, bl);
      encode(prefix, bl);
      encode(status, bl);
@@ -250,10 +350,12 @@ public:
      encode(mp_expiration, bl);
      encode(dm_expiration, bl);
      encode(filter, bl);
+     encode(transitions, bl);
+     encode(noncur_transitions, bl);
      ENCODE_FINISH(bl);
    }
    void decode(bufferlist::const_iterator& bl) {
-     DECODE_START_LEGACY_COMPAT_LEN(5, 1, 1, bl);
+     DECODE_START_LEGACY_COMPAT_LEN(6, 1, 1, bl);
      decode(id, bl);
      decode(prefix, bl);
      decode(status, bl);
@@ -270,6 +372,10 @@ public:
      if (struct_v >= 5) {
        decode(filter, bl);
      }
+     if (struct_v >= 6) {
+       decode(transitions, bl);
+       decode(noncur_transitions, bl);
+     }
      DECODE_FINISH(bl);
    }
   void dump(Formatter *f) const;
@@ -278,6 +384,14 @@ public:
 };
 WRITE_CLASS_ENCODER(LCRule)
 
+struct transition_action
+{
+  int days;
+  boost::optional<ceph::real_time> date;
+  int storage_class;
+  transition_action() : days(0), storage_class(standard_ia) {}
+};
+
 struct lc_op
 {
   bool status{false};
@@ -287,6 +401,8 @@ struct lc_op
   int mp_expiration{0};
   boost::optional<ceph::real_time> expiration_date;
   boost::optional<RGWObjTags> obj_tags;
+  map<int, transition_action> transitions;
+  map<int, transition_action> noncur_transitions;
   
   void dump(Formatter *f) const;
 };
index 8663b445d08e17d6398d1d549d9229095ce85613..21bf202b61fc168d9d8d2071370cb6048df85746 100644 (file)
@@ -34,12 +34,7 @@ bool LCExpiration_S3::xml_end(const char * el) {
   } else {
     date = lc_date->get_data();
     //We need return xml error according to S3
-    boost::optional<ceph::real_time> expiration_date = ceph::from_iso_8601(date);
-    if (boost::none == expiration_date) {
-      return false;
-    }
-    struct timespec expiration_time = ceph::real_clock::to_timespec(*expiration_date);
-    if (expiration_time.tv_sec % (24*60*60) || expiration_time.tv_nsec) {
+    if (!check_date(date)) {
       return false;
     }
   }
@@ -110,6 +105,51 @@ bool LCFilter_S3::xml_end(const char* el) {
   return !(single_cond && num_conditions > 1);
 }
 
+bool LCTransition_S3::xml_end(const char* el) {
+  LCDays_S3 *lc_days = static_cast<LCDays_S3 *>(find_first("Days"));
+  LCDate_S3 *lc_date = static_cast<LCDate_S3 *>(find_first("Date"));
+  if ((lc_days && lc_date) || (!lc_days && !lc_date)) {
+    return false;
+  }
+  if (lc_days) {
+    days = lc_days->get_data();
+  } else {
+    date = lc_date->get_data();
+    //We need return xml error according to S3
+    if (!check_date(date)) {
+      return false;
+    }
+  }
+  LCStorageClass_S3 *lc_storage_class = static_cast<LCStorageClass_S3 *>(find_first("StorageClass"));
+  if (!lc_storage_class) {
+    return false;
+  }
+  storage_class = lc_storage_class->get_data();
+  if (storage_class.compare("STANDARD_IA") != 0 && storage_class.compare("ONEZONE_IA") != 0 &&
+      storage_class.compare("GLACIER") != 0) {
+    return false;
+  }
+  return true;
+}
+
+bool LCNoncurTransition_S3::xml_end(const char* el) {
+  LCDays_S3 *lc_noncur_days = static_cast<LCDays_S3 *>(find_first("NoncurrentDays"));
+  if (!lc_noncur_days) {
+    return false;
+  }
+  days = lc_noncur_days->get_data();
+  LCStorageClass_S3 *lc_storage_class = static_cast<LCStorageClass_S3 *>(find_first("StorageClass"));
+  if (!lc_storage_class) {
+    return false;
+  }
+  storage_class = lc_storage_class->get_data();
+  if (storage_class.compare("STANDARD_IA") != 0 && storage_class.compare("ONEZONE_IA") != 0 &&
+      storage_class.compare("GLACIER") != 0) {
+    return false;
+  }
+  return true;
+}
+
 
 bool LCRule_S3::xml_end(const char *el) {
   LCID_S3 *lc_id;
@@ -119,6 +159,8 @@ bool LCRule_S3::xml_end(const char *el) {
   LCNoncurExpiration_S3 *lc_noncur_expiration;
   LCMPExpiration_S3 *lc_mp_expiration;
   LCFilter_S3 *lc_filter;
+  LCTransition_S3 *lc_transition;
+  LCNoncurTransition_S3 *lc_noncur_transition;
   id.clear();
   prefix.clear();
   status.clear();
@@ -168,7 +210,13 @@ bool LCRule_S3::xml_end(const char *el) {
   lc_expiration = static_cast<LCExpiration_S3 *>(find_first("Expiration"));
   lc_noncur_expiration = static_cast<LCNoncurExpiration_S3 *>(find_first("NoncurrentVersionExpiration"));
   lc_mp_expiration = static_cast<LCMPExpiration_S3 *>(find_first("AbortIncompleteMultipartUpload"));
-  if (!lc_expiration && !lc_noncur_expiration && !lc_mp_expiration) {
+
+  XMLObjIter iter = find("Transition");
+  lc_transition = static_cast<LCTransition_S3 *>(iter.get_next());
+  XMLObjIter noncur_iter = find("NoncurrentVersionTransition");
+  lc_noncur_transition = static_cast<LCNoncurTransition_S3 *>(noncur_iter.get_next());
+
+  if (!lc_expiration && !lc_noncur_expiration && !lc_mp_expiration && !lc_transition && !lc_noncur_transition) {
     return false;
   } else {
     if (lc_expiration) {
@@ -186,8 +234,19 @@ bool LCRule_S3::xml_end(const char *el) {
     if (lc_mp_expiration) {
       mp_expiration = *lc_mp_expiration;
     }
+    while (lc_transition) {
+      if (!add_transition(lc_transition)) {
+        return false;
+      }
+      lc_transition = static_cast<LCTransition_S3 *>(iter.get_next());
+    }
+    while (lc_noncur_transition) {
+      if (!add_noncur_transition(lc_noncur_transition)) {
+        return false;
+      }
+      lc_noncur_transition = static_cast<LCNoncurTransition_S3 *>(noncur_iter.get_next());
+    }
   }
-
   return true;
 }
 
@@ -213,6 +272,18 @@ void LCRule_S3::to_xml(ostream& out) {
     LCMPExpiration_S3& mp_expir = static_cast<LCMPExpiration_S3&>(mp_expiration);
     mp_expir.to_xml(out);
   }
+  if (!transitions.empty()) {
+    for (auto &elem : transitions) {
+      LCTransition_S3& tran = static_cast<LCTransition_S3&>(elem.second);
+      tran.to_xml(out);
+    }
+  }
+  if (!noncur_transitions.empty()) {
+    for (auto &elem : noncur_transitions) {
+      LCNoncurTransition_S3& noncur_tran = static_cast<LCNoncurTransition_S3&>(elem.second);
+      noncur_tran.to_xml(out);
+    }
+  }
   out << "</Rule>";
 }
 
@@ -277,6 +348,25 @@ XMLObj *RGWLCXMLParser_S3::alloc_obj(const char *el)
     obj = new LCMPExpiration_S3();
   } else if (strcmp(el, "DaysAfterInitiation") == 0) {
     obj = new LCDays_S3();
+  } else if (strcmp(el, "StorageClass") == 0) {
+    obj = new LCStorageClass_S3();
+  } else if (strcmp(el, "Transition") == 0) {
+    obj = new LCTransition_S3();
+  } else if (strcmp(el, "NoncurrentVersionTransition") == 0) {
+    obj = new LCNoncurTransition_S3();
   }
   return obj;
 }
+
+bool check_date(const string& _date)
+{
+  boost::optional<ceph::real_time> date = ceph::from_iso_8601(_date);
+  if (boost::none == date) {
+    return false;
+  }
+  struct timespec time = ceph::real_clock::to_timespec(*date);
+  if (time.tv_sec % (24*60*60) || time.tv_nsec) {
+    return false;
+  }
+  return true;
+}
index d344fd2987d729d9d1b8ed62cf268b70429ac23a..affa3b758ec31f39ffdcf0d2843f3aff2291a11e 100644 (file)
@@ -186,6 +186,64 @@ public:
   }
 };
 
+class LCStorageClass_S3 : public XMLObj
+{
+public:
+  LCStorageClass_S3() {}
+  ~LCStorageClass_S3() override {}
+  string& to_str() { return data; }
+};
+
+class LCTransition_S3 : public LCTransition, public XMLObj
+{
+public:
+  LCTransition_S3() {}
+  ~LCTransition_S3() {}
+
+  bool xml_end(const char *el) override;
+  void to_xml(ostream& out) {
+    out << "<Transition>";
+    if (!days.empty()) {
+      out << "<Days>" << days << "</Days>";
+    } else {
+      out << "<Date>" << date << "</Date>";
+    }
+    out << "<StorageClass>" << storage_class << "</StorageClass>" << "</Transition>";
+  }
+
+  void dump_xml(Formatter *f) const {
+    f->open_object_section("Transition");
+    if (!days.empty()) {
+      encode_xml("Days", days, f);
+    } else {
+      encode_xml("Date", date, f);
+    }
+    encode_xml("StorageClass", storage_class, f);
+    f->close_section();
+  }
+};
+
+class LCNoncurTransition_S3 : public LCTransition, public XMLObj
+{
+public:
+  LCNoncurTransition_S3() {}
+  ~LCNoncurTransition_S3() {}
+
+  bool xml_end(const char *el) override;
+  void to_xml(ostream& out) {
+    out << "<NoncurrentVersionTransition>" << "<NoncurrentDays>" << days << "</NoncurrentDays>"
+        << "<StorageClass>" << storage_class << "</StorageClass>" << "</NoncurrentVersionTransition>";
+  }
+
+  void dump_xml(Formatter *f) const {
+    f->open_object_section("NoncurrentVersionTransition");
+    encode_xml("NoncurrentDays", days, f);
+    encode_xml("StorageClass", storage_class, f);
+    f->close_section();
+  }
+};
+
+
 class LCRule_S3 : public LCRule, public XMLObj
 {
 private:
@@ -221,7 +279,18 @@ public:
       const LCMPExpiration_S3& mp_expir = static_cast<const LCMPExpiration_S3&>(mp_expiration);
       mp_expir.dump_xml(f);
     }
-
+    if (!transitions.empty()) {
+      for (auto &elem : transitions) {
+        const LCTransition_S3& tran = static_cast<const LCTransition_S3&>(elem.second);
+        tran.dump_xml(f);
+      }
+    }
+    if (!noncur_transitions.empty()) {
+      for (auto &elem : noncur_transitions) {
+        const LCNoncurTransition_S3& noncur_tran = static_cast<const LCNoncurTransition_S3&>(elem.second);
+        noncur_tran.dump_xml(f);
+      }
+    }
     f->close_section(); // Rule
   }
 
@@ -261,5 +330,5 @@ public:
   void dump_xml(Formatter *f) const;
 };
 
-
+bool check_date(const string& _date);
 #endif