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 <id> --storage-class <class>" will be
used to add tier storage classes as well but with extra tier-config options mentioned below -
--tier-type : "cloud"
--tier-config : [<key,value>,]
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 <skoduri@redhat.com>
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()) {
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)
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
}
}
+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;
+}
};
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<string, RGWTierACLMapping> 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<std::string> tags;
std::set<std::string> storage_classes;
+ std::map<std::string, RGWZoneGroupPlacementTier> tier_targets;
bool user_permitted(const std::list<std::string>& user_tags) const {
if (tags.empty()) {
}
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) {
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;