From c63d16ff96203ca768c4733bc757cc08c9e4712f Mon Sep 17 00:00:00 2001 From: Soumya Koduri Date: Sat, 11 Jul 2020 22:35:04 +0530 Subject: [PATCH] rgw/CloudTransition: Add new options to configure tier endpoint As mentioned in https://docs.google.com/document/d/1IoeITPCF64A5W-UA-9Y3Vp2oSfz3xVQHu31GTu3u3Ug/edit, the tier storage class will be configured at zonegroup level. So the existing CLI "radosgw-admin zonegroup placement add --storage-class " will be used to add tier storage classes as well but with extra tier-config options mentioned below - --tier-type : "cloud" --tier-config : [,] These tier options are already defined to configure cloud sync module which are being reused here. TODO: * Add multipart options (if any , like part size, threshold) * Document * Test upgrade/downgrade Signed-off-by: Soumya Koduri --- src/rgw/rgw_admin.cc | 51 ++++++++++++++++ src/rgw/rgw_json_enc.cc | 70 ++++++++++++++++++++++ src/rgw/rgw_zone.cc | 84 ++++++++++++++++++++++++++ src/rgw/rgw_zone.h | 129 +++++++++++++++++++++++++++++++++++++++- 4 files changed, 332 insertions(+), 2 deletions(-) diff --git a/src/rgw/rgw_admin.cc b/src/rgw/rgw_admin.cc index 703930045722f..2378499fa94ef 100644 --- a/src/rgw/rgw_admin.cc +++ b/src/rgw/rgw_admin.cc @@ -5049,6 +5049,57 @@ int main(int argc, const char **argv) target.tags.insert(t); } target.storage_classes.insert(rule.get_storage_class()); + + /* Tier options */ + bool tier_class = false; + std::string storage_class = rule.get_storage_class(); + RGWZoneGroupPlacementTier t{storage_class}; + RGWZoneGroupPlacementTier *pt = &t; + + auto ptiter = target.tier_targets.find(storage_class); + if (ptiter != target.tier_targets.end()) { + pt = &ptiter->second; + tier_class = true; + } else if (tier_type_specified && tier_type == "cloud") { + /* we support only cloud tier-type for now. + * Once set cant be reset. */ + tier_class = true; + pt->tier_type = tier_type; + } + + if (tier_class) { + if (tier_config_add.size() > 0) { + JSONFormattable tconfig; + for (auto add : tier_config_add) { + int r = tconfig.set(add.first, add.second); + if (r < 0) { + cerr << "ERROR: failed to set configurable: " << add << std::endl; + return EINVAL; + } + } + int r = pt->update_params(tconfig); + if (r < 0) { + cerr << "ERROR: failed to update tier_config options"<< std::endl; + } + } + if (tier_config_rm.size() > 0) { + JSONFormattable tconfig; + for (auto add : tier_config_rm) { + int r = tconfig.set(add.first, add.second); + if (r < 0) { + cerr << "ERROR: failed to set configurable: " << add << std::endl; + return EINVAL; + } + } + int r = pt->clear_params(tconfig); + if (r < 0) { + cerr << "ERROR: failed to update tier_config options"<< std::endl; + } + } + + target.tier_targets.emplace(std::make_pair(storage_class, *pt)); + } + } else if (opt_cmd == OPT::ZONEGROUP_PLACEMENT_RM) { if (!opt_storage_class || opt_storage_class->empty()) { diff --git a/src/rgw/rgw_json_enc.cc b/src/rgw/rgw_json_enc.cc index 99892a44baee4..9f8ab1626c26c 100644 --- a/src/rgw/rgw_json_enc.cc +++ b/src/rgw/rgw_json_enc.cc @@ -1402,11 +1402,80 @@ void RGWZone::decode_json(JSONObj *obj) JSONDecoder::decode_json("redirect_zone", redirect_zone, obj); } +void RGWTierACLMapping::dump(Formatter *f) const +{ + string s; + switch (type) { + case ACL_TYPE_EMAIL_USER: + s = "email"; + break; + case ACL_TYPE_GROUP: + s = "uri"; + break; + default: + s = "id"; + break; + } + encode_json("type", s, f); + encode_json("source_id", source_id, f); + encode_json("dest_id", dest_id, f); +} + +void RGWTierACLMapping::decode_json(JSONObj *obj) +{ + string s; + JSONDecoder::decode_json("type", s, obj); + if (s == "email") { + type = ACL_TYPE_EMAIL_USER; + } else if (s == "uri") { + type = ACL_TYPE_GROUP; + } else { + type = ACL_TYPE_CANON_USER; + } + + JSONDecoder::decode_json("source_id", source_id, obj); + JSONDecoder::decode_json("dest_id", dest_id, obj); +} + +void RGWZoneGroupPlacementTier::dump(Formatter *f) const +{ + encode_json("storage_class", storage_class, f); + encode_json("tier_type", tier_type, f); + encode_json("endpoint", endpoint, f); + encode_json("access_key", key.id, f); + encode_json("secret", key.key, f); + string s = (host_style == PathStyle ? "path" : "virtual"); + encode_json("host_style", s, f); + encode_json("tier_storage_class", tier_storage_class, f); + encode_json("target_path", target_path, f); + encode_json("acl_mappings", acl_mappings, f); +} + +void RGWZoneGroupPlacementTier::decode_json(JSONObj *obj) +{ + JSONDecoder::decode_json("storage_class", storage_class, obj); + JSONDecoder::decode_json("tier_type", tier_type, obj); + JSONDecoder::decode_json("endpoint", endpoint, obj); + JSONDecoder::decode_json("access_key", key.id, obj); + JSONDecoder::decode_json("secret", key.key, obj); + string s; + JSONDecoder::decode_json("host_style", s, obj); + if (s != "virtual") { + host_style = PathStyle; + } else { + host_style = VirtualStyle; + } + JSONDecoder::decode_json("tier_storage_class", tier_storage_class, obj); + JSONDecoder::decode_json("target_path", target_path, obj); + JSONDecoder::decode_json("acl_mappings", acl_mappings, obj); +} + void RGWZoneGroupPlacementTarget::dump(Formatter *f) const { encode_json("name", name, f); encode_json("tags", tags, f); encode_json("storage_classes", storage_classes, f); + encode_json("tier_targets", tier_targets, f); } void RGWZoneGroupPlacementTarget::decode_json(JSONObj *obj) @@ -1417,6 +1486,7 @@ void RGWZoneGroupPlacementTarget::decode_json(JSONObj *obj) if (storage_classes.empty()) { storage_classes.insert(RGW_STORAGE_CLASS_STANDARD); } + JSONDecoder::decode_json("tier_targets", tier_targets, obj); } void RGWZoneGroup::dump(Formatter *f) const diff --git a/src/rgw/rgw_zone.cc b/src/rgw/rgw_zone.cc index 6d9f8b05140ad..1d013ae5a97c0 100644 --- a/src/rgw/rgw_zone.cc +++ b/src/rgw/rgw_zone.cc @@ -2081,4 +2081,88 @@ void RGWZoneGroupMap::decode(bufferlist::const_iterator& bl) { } } +int RGWZoneGroupPlacementTier::update_params(const JSONFormattable& config) +{ + + if (config.exists("endpoint")) { + endpoint = config["endpoint"]; + } + if (config.exists("target_path")) { + target_path = config["target_path"]; + } + if (config.exists("host_style")) { + string s; + s = config["host_style"]; + if (s != "virtual") { + host_style = PathStyle; + } else { + host_style = VirtualStyle; + } + } + if (config.exists("tier_storage_class")) { + tier_storage_class = config["tier_storage_class"]; + } + if (config.exists("access_key")) { + key.id = config["access_key"]; + } + if (config.exists("secret")) { + key.key = config["secret"]; + } + if (config.exists("acls")) { + const JSONFormattable& cc = config["acls"]; + if (cc.is_array()) { + for (auto& c : cc.array()) { + RGWTierACLMapping m; + m.init(c); + if (!m.source_id.empty()) { + acl_mappings[m.source_id] = m; + } + } + } else { + RGWTierACLMapping m; + m.init(cc); + if (!m.source_id.empty()) { + acl_mappings[m.source_id] = m; + } + } + } + return 0; +} +int RGWZoneGroupPlacementTier::clear_params(const JSONFormattable& config) +{ + if (config.exists("endpoint")) { + endpoint.clear(); + } + if (config.exists("target_path")) { + target_path.clear(); + } + if (config.exists("host_style")) { + /* default */ + host_style = PathStyle; + } + if (config.exists("tier_storage_class")) { + tier_storage_class.clear(); + } + if (config.exists("access_key")) { + key.id.clear(); + } + if (config.exists("secret")) { + key.key.clear(); + } + if (config.exists("acls")) { + const JSONFormattable& cc = config["acls"]; + if (cc.is_array()) { + for (auto& c : cc.array()) { + RGWTierACLMapping m; + m.init(c); + acl_mappings.erase(m.source_id); + } + } else { + RGWTierACLMapping m; + m.init(cc); + acl_mappings.erase(m.source_id); + } + } + return 0; +} diff --git a/src/rgw/rgw_zone.h b/src/rgw/rgw_zone.h index 2823d54fc71bb..c145ca1b8423b 100644 --- a/src/rgw/rgw_zone.h +++ b/src/rgw/rgw_zone.h @@ -679,10 +679,131 @@ struct RGWDefaultZoneGroupInfo { }; WRITE_CLASS_ENCODER(RGWDefaultZoneGroupInfo) +struct RGWTierACLMapping { + ACLGranteeTypeEnum type{ACL_TYPE_CANON_USER}; + std::string source_id; + std::string dest_id; + + RGWTierACLMapping() = default; + + RGWTierACLMapping(ACLGranteeTypeEnum t, + const string& s, + const string& d) : type(t), + source_id(s), + dest_id(d) {} + + void init(const JSONFormattable& config) { + const string& t = config["type"]; + + if (t == "email") { + type = ACL_TYPE_EMAIL_USER; + } else if (t == "uri") { + type = ACL_TYPE_GROUP; + } else { + type = ACL_TYPE_CANON_USER; + } + + source_id = config["source_id"]; + dest_id = config["dest_id"]; + } + + void encode(bufferlist& bl) const { + ENCODE_START(1, 1, bl); + string s; + switch (type) { + case ACL_TYPE_EMAIL_USER: + s = "email"; + break; + case ACL_TYPE_GROUP: + s = "uri"; + break; + default: + s = "id"; + break; + } + encode(s, bl); + encode(source_id, bl); + encode(dest_id, bl); + ENCODE_FINISH(bl); + } + + void decode(bufferlist::const_iterator& bl) { + DECODE_START(1, bl); + string s; + decode(s, bl); + if (s == "email") { + type = ACL_TYPE_EMAIL_USER; + } else if (s == "uri") { + type = ACL_TYPE_GROUP; + } else { + type = ACL_TYPE_CANON_USER; + } + decode(source_id, bl); + decode(dest_id, bl); + DECODE_FINISH(bl); + } + void dump(Formatter *f) const; + void decode_json(JSONObj *obj); +}; +WRITE_CLASS_ENCODER(RGWTierACLMapping) + +struct RGWZoneGroupPlacementTier { + std::string storage_class; + std::string tier_type; + std::string endpoint; + RGWAccessKey key; + HostStyle host_style{PathStyle}; + string tier_storage_class; + + /* Should below be bucket/zone specific?? */ + string target_path; + map acl_mappings; + + int update_params(const JSONFormattable& config); + int clear_params(const JSONFormattable& config); + + void encode(bufferlist& bl) const { + ENCODE_START(1, 1, bl); + encode(storage_class, bl); + encode(tier_type, bl); + encode(endpoint, bl); + encode(key, bl); + string s = (host_style == PathStyle ? "path" : "virtual"); + encode(s, bl); + encode(tier_storage_class, bl); + encode(target_path, bl); + encode(acl_mappings, bl); + ENCODE_FINISH(bl); + } + + void decode(bufferlist::const_iterator& bl) { + DECODE_START(1, bl); + decode(storage_class, bl); + decode(tier_type, bl); + decode(endpoint, bl); + decode(key, bl); + string s; + decode(s, bl); + if (s != "virtual") { + host_style = PathStyle; + } else { + host_style = VirtualStyle; + } + decode(tier_storage_class, bl); + decode(target_path, bl); + decode(acl_mappings, bl); + DECODE_FINISH(bl); + } + void dump(Formatter *f) const; + void decode_json(JSONObj *obj); +}; +WRITE_CLASS_ENCODER(RGWZoneGroupPlacementTier) + struct RGWZoneGroupPlacementTarget { std::string name; std::set tags; std::set storage_classes; + std::map tier_targets; bool user_permitted(const std::list& user_tags) const { if (tags.empty()) { @@ -697,15 +818,16 @@ struct RGWZoneGroupPlacementTarget { } void encode(bufferlist& bl) const { - ENCODE_START(2, 1, bl); + ENCODE_START(3, 1, bl); encode(name, bl); encode(tags, bl); encode(storage_classes, bl); + encode(tier_targets, bl); ENCODE_FINISH(bl); } void decode(bufferlist::const_iterator& bl) { - DECODE_START(2, bl); + DECODE_START(3, bl); decode(name, bl); decode(tags, bl); if (struct_v >= 2) { @@ -714,6 +836,9 @@ struct RGWZoneGroupPlacementTarget { if (storage_classes.empty()) { storage_classes.insert(RGW_STORAGE_CLASS_STANDARD); } + if (struct_v >= 3) { + decode(tier_targets, bl); + } DECODE_FINISH(bl); } void dump(Formatter *f) const; -- 2.39.5