From: Zhang Shaowen Date: Mon, 23 Jul 2018 09:43:18 +0000 (+0800) Subject: rgw: support object transition in lifecycle config set. X-Git-Tag: v14.1.0~314^2~37 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=97678bb66a64a72da9109d333decd0dda248c6fc;p=ceph.git rgw: support object transition in lifecycle config set. Signed-off-by: Zhang Shaowen --- diff --git a/src/rgw/rgw_lc.cc b/src/rgw/rgw_lc.cc index fe056655e2a..e6ab1d8d5b7 100644 --- a/src/rgw/rgw_lc.cc +++ b/src/rgw/rgw_lc.cc @@ -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 diff --git a/src/rgw/rgw_lc.h b/src/rgw/rgw_lc.h index 687b9aaa924..04c5dff8c4b 100644 --- a/src/rgw/rgw_lc.h +++ b/src/rgw/rgw_lc.h @@ -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 transitions; + map noncur_transitions; bool dm_expiration = false; public: @@ -210,6 +292,14 @@ public: return dm_expiration; } + map& get_transitions() { + return transitions; + } + + map& 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 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 expiration_date; boost::optional obj_tags; + map transitions; + map noncur_transitions; void dump(Formatter *f) const; }; diff --git a/src/rgw/rgw_lc_s3.cc b/src/rgw/rgw_lc_s3.cc index 8663b445d08..21bf202b61f 100644 --- a/src/rgw/rgw_lc_s3.cc +++ b/src/rgw/rgw_lc_s3.cc @@ -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 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(find_first("Days")); + LCDate_S3 *lc_date = static_cast(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(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(find_first("NoncurrentDays")); + if (!lc_noncur_days) { + return false; + } + days = lc_noncur_days->get_data(); + LCStorageClass_S3 *lc_storage_class = static_cast(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(find_first("Expiration")); lc_noncur_expiration = static_cast(find_first("NoncurrentVersionExpiration")); lc_mp_expiration = static_cast(find_first("AbortIncompleteMultipartUpload")); - if (!lc_expiration && !lc_noncur_expiration && !lc_mp_expiration) { + + XMLObjIter iter = find("Transition"); + lc_transition = static_cast(iter.get_next()); + XMLObjIter noncur_iter = find("NoncurrentVersionTransition"); + lc_noncur_transition = static_cast(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(iter.get_next()); + } + while (lc_noncur_transition) { + if (!add_noncur_transition(lc_noncur_transition)) { + return false; + } + lc_noncur_transition = static_cast(noncur_iter.get_next()); + } } - return true; } @@ -213,6 +272,18 @@ void LCRule_S3::to_xml(ostream& out) { LCMPExpiration_S3& mp_expir = static_cast(mp_expiration); mp_expir.to_xml(out); } + if (!transitions.empty()) { + for (auto &elem : transitions) { + LCTransition_S3& tran = static_cast(elem.second); + tran.to_xml(out); + } + } + if (!noncur_transitions.empty()) { + for (auto &elem : noncur_transitions) { + LCNoncurTransition_S3& noncur_tran = static_cast(elem.second); + noncur_tran.to_xml(out); + } + } out << ""; } @@ -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 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; +} diff --git a/src/rgw/rgw_lc_s3.h b/src/rgw/rgw_lc_s3.h index d344fd2987d..affa3b758ec 100644 --- a/src/rgw/rgw_lc_s3.h +++ b/src/rgw/rgw_lc_s3.h @@ -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 << ""; + if (!days.empty()) { + out << "" << days << ""; + } else { + out << "" << date << ""; + } + out << "" << storage_class << "" << ""; + } + + 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 << "" << "" << days << "" + << "" << storage_class << "" << ""; + } + + 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(mp_expiration); mp_expir.dump_xml(f); } - + if (!transitions.empty()) { + for (auto &elem : transitions) { + const LCTransition_S3& tran = static_cast(elem.second); + tran.dump_xml(f); + } + } + if (!noncur_transitions.empty()) { + for (auto &elem : noncur_transitions) { + const LCNoncurTransition_S3& noncur_tran = static_cast(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