]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw/pubsub: use rgw_owner for topic ownership
authorCasey Bodley <cbodley@redhat.com>
Tue, 12 Dec 2023 21:36:04 +0000 (16:36 -0500)
committerCasey Bodley <cbodley@redhat.com>
Wed, 10 Apr 2024 16:53:05 +0000 (12:53 -0400)
allow topics to be owned by accounts instead of users. radosgw-admin
topic list can now filter by --account-id

Signed-off-by: Casey Bodley <cbodley@redhat.com>
src/rgw/driver/rados/rgw_sal_rados.cc
src/rgw/driver/rados/topic.cc
src/rgw/rgw_admin.cc
src/rgw/rgw_pubsub.cc
src/rgw/rgw_pubsub.h
src/rgw/rgw_rest_pubsub.cc
src/test/rgw/bucket_notification/test_bn.py

index d0a3bac1896ac592fa50899d9e9bc68d5dfaf284..e965a8e233a0210c8940bcf7fda6be4bb47f9be4 100644 (file)
@@ -1317,7 +1317,7 @@ int RadosStore::update_bucket_topic_mapping(const rgw_pubsub_topic& topic,
                                             const DoutPrefixProvider* dpp) {
   librados::Rados& rados = *getRados()->get_rados_handle();
   const RGWZoneParams& zone = svc()->zone->get_zone_params();
-  const std::string key = get_topic_metadata_key(topic.user.tenant, topic.name);
+  const std::string key = get_topic_metadata_key(topic);
   int ret = 0;
   if (add_mapping) {
     ret = rgwrados::topic::link_bucket(dpp, y, rados, zone, key, bucket_key);
@@ -1343,7 +1343,7 @@ int RadosStore::get_bucket_topic_mapping(const rgw_pubsub_topic& topic,
 {
   librados::Rados& rados = *getRados()->get_rados_handle();
   const RGWZoneParams& zone = svc()->zone->get_zone_params();
-  const std::string key = get_topic_metadata_key(topic.user.tenant, topic.name);
+  const std::string key = get_topic_metadata_key(topic);
   constexpr int max_chunk = 1024;
   std::string marker;
 
index 86ce6bb819b4d5faa132c7023c4eb24bc9d3befd..9366b6fa3dda13ba17609a2a28ddf37dce6bc425 100644 (file)
@@ -99,7 +99,7 @@ int write(const DoutPrefixProvider* dpp, optional_yield y,
           const rgw_pubsub_topic& info, RGWObjVersionTracker& objv,
           ceph::real_time mtime, bool exclusive)
 {
-  const std::string topic_key = get_topic_metadata_key(info.user.tenant, info.name);
+  const std::string topic_key = get_topic_metadata_key(info);
   const rgw_raw_obj obj = get_topic_obj(zone, topic_key);
 
   bufferlist bl;
index c318490ed00ed7496271164906d3dd9922721a9d..64e7018037ebd450e7aa86ecfe9f3fb3b79305f9 100644 (file)
@@ -10739,6 +10739,13 @@ next:
     RGWPubSub ps(driver, tenant, *site);
     std::string next_token = marker;
 
+    std::optional<rgw_owner> owner;
+    if (!rgw::sal::User::empty(user)) {
+      owner = user->get_id();
+    } else if (!account_id.empty()) {
+      owner = rgw_account_id{account_id};
+    }
+
     formatter->open_object_section("result");
     formatter->open_array_section("topics");
     do {
@@ -10750,7 +10757,7 @@ next:
         return -ret;
       }
       for (const auto& [_, topic] : result.topics) {
-        if (!rgw::sal::User::empty(user) && user->get_id() != topic.user) {
+        if (owner && *owner != topic.owner) {
           continue;
         }
         std::set<std::string> subscribed_buckets;
index 46fb56874b39b95c2a74504e6b073fe190e363b0..579142a84c7af8ddf8bf4ae998558941f33c5d86 100644 (file)
@@ -12,6 +12,7 @@
 #include "rgw_pubsub_push.h"
 #include "rgw_bucket.h"
 #include "common/errno.h"
+#include "include/function2.hpp"
 #include <regex>
 #include <algorithm>
 
@@ -26,6 +27,16 @@ std::string get_topic_metadata_key(std::string_view tenant,
   return string_cat_reserve(tenant, topic_tenant_delim, topic_name);
 }
 
+std::string get_topic_metadata_key(const rgw_pubsub_topic& topic)
+{
+  // use account id or tenant name
+  std::string_view tenant = std::visit(fu2::overload(
+      [] (const rgw_user& u) -> std::string_view { return u.tenant; },
+      [] (const rgw_account_id& a) -> std::string_view { return a; }
+      ), topic.owner);
+  return get_topic_metadata_key(tenant, topic.name);
+}
+
 void parse_topic_metadata_key(const std::string& key,
                               std::string& tenant,
                               std::string& name)
@@ -367,7 +378,7 @@ void rgw_pubsub_s3_event::dump(Formatter *f) const {
 
 void rgw_pubsub_topic::dump(Formatter *f) const
 {
-  encode_json("user", user, f);
+  encode_json("owner", owner, f);
   encode_json("name", name, f);
   encode_json("dest", dest, f);
   encode_json("arn", arn, f);
@@ -377,7 +388,7 @@ void rgw_pubsub_topic::dump(Formatter *f) const
 
 void rgw_pubsub_topic::dump_xml(Formatter *f) const
 {
-  encode_xml("User", user, f);
+  encode_xml("User", to_string(owner), f);
   encode_xml("Name", name, f);
   encode_xml("EndPoint", dest, f);
   encode_xml("TopicArn", arn, f);
@@ -395,9 +406,7 @@ void encode_xml_key_value_entry(const std::string& key, const std::string& value
 void rgw_pubsub_topic::dump_xml_as_attributes(Formatter *f) const
 {
   f->open_array_section("Attributes");
-  std::string str_user;
-  user.to_str(str_user);
-  encode_xml_key_value_entry("User", str_user, f);
+  encode_xml_key_value_entry("User", to_string(owner), f);
   encode_xml_key_value_entry("Name", name, f);
   encode_xml_key_value_entry("EndPoint", dest.to_json_str(), f);
   encode_xml_key_value_entry("TopicArn", arn, f);
@@ -408,7 +417,7 @@ void rgw_pubsub_topic::dump_xml_as_attributes(Formatter *f) const
 }
 
 void rgw_pubsub_topic::decode_json(JSONObj* f) {
-  JSONDecoder::decode_json("user", user, f);
+  JSONDecoder::decode_json("owner", owner, f);
   JSONDecoder::decode_json("name", name, f);
   JSONDecoder::decode_json("dest", dest, f);
   JSONDecoder::decode_json("arn", arn, f);
@@ -971,7 +980,7 @@ int RGWPubSub::create_topic(const DoutPrefixProvider* dpp,
                             const std::string& name,
                             const rgw_pubsub_dest& dest, const std::string& arn,
                             const std::string& opaque_data,
-                            const rgw_user& user,
+                            const rgw_owner& owner,
                             const std::string& policy_text,
                             optional_yield y) const {
   if (use_notification_v2) {
@@ -981,7 +990,7 @@ int RGWPubSub::create_topic(const DoutPrefixProvider* dpp,
       return -ERR_SERVICE_UNAVAILABLE;
     }
     rgw_pubsub_topic new_topic;
-    new_topic.user = user;
+    new_topic.owner = owner;
     new_topic.name = name;
     new_topic.dest = dest;
     new_topic.arn = arn;
@@ -1000,7 +1009,7 @@ int RGWPubSub::create_topic(const DoutPrefixProvider* dpp,
   }
  
   rgw_pubsub_topic& new_topic = topics.topics[name];
-  new_topic.user = user;
+  new_topic.owner = owner;
   new_topic.name = name;
   new_topic.dest = dest;
   new_topic.arn = arn;
index 89b6e5d72519630bc319c01ea71946bcc198ab1e..6891c6ebd159f467d7925d088c3a187b870bc19c 100644 (file)
@@ -3,7 +3,8 @@
 
 #pragma once
 
-#include "rgw_sal.h"
+#include "common/versioned_variant.h"
+#include "rgw_sal_fwd.h"
 #include "rgw_tools.h"
 #include "rgw_zone.h"
 #include "rgw_notify_event_type.h"
@@ -394,7 +395,7 @@ struct rgw_pubsub_dest {
 WRITE_CLASS_ENCODER(rgw_pubsub_dest)
 
 struct rgw_pubsub_topic {
-  rgw_user user;
+  rgw_owner owner;
   std::string name;
   rgw_pubsub_dest dest;
   std::string arn;
@@ -403,7 +404,8 @@ struct rgw_pubsub_topic {
 
   void encode(bufferlist& bl) const {
     ENCODE_START(4, 1, bl);
-    encode(user, bl);
+    // converted from rgw_user to rgw_owner
+    ceph::converted_variant::encode(owner, bl);
     encode(name, bl);
     encode(dest, bl);
     encode(arn, bl);
@@ -414,7 +416,8 @@ struct rgw_pubsub_topic {
 
   void decode(bufferlist::const_iterator& bl) {
     DECODE_START(4, bl);
-    decode(user, bl);
+    // converted from rgw_user to rgw_owner
+    ceph::converted_variant::decode(owner, bl);
     decode(name, bl);
     if (struct_v >= 2) {
       decode(dest, bl);
@@ -429,18 +432,10 @@ struct rgw_pubsub_topic {
     DECODE_FINISH(bl);
   }
 
-  std::string to_str() const {
-    return user.tenant + "/" + name;
-  }
-
   void dump(Formatter *f) const;
   void dump_xml(Formatter *f) const;
   void dump_xml_as_attributes(Formatter *f) const;
   void decode_json(JSONObj* obj);
-
-  bool operator<(const rgw_pubsub_topic& t) const {
-    return to_str().compare(t.to_str());
-  }
 };
 WRITE_CLASS_ENCODER(rgw_pubsub_topic)
 
@@ -640,7 +635,7 @@ public:
   // return 0 on success, error code otherwise
   int create_topic(const DoutPrefixProvider* dpp, const std::string& name,
                    const rgw_pubsub_dest& dest, const std::string& arn,
-                   const std::string& opaque_data, const rgw_user& user,
+                   const std::string& opaque_data, const rgw_owner& owner,
                    const std::string& policy_text, optional_yield y) const;
   // remove a topic according to its name
   // if the topic does not exists it is a no-op (considered success)
@@ -690,8 +685,9 @@ int get_bucket_notifications(const DoutPrefixProvider* dpp,
                              rgw_pubsub_bucket_topics& bucket_topics);
 
 // format and parse topic metadata keys as tenant:name
-std::string get_topic_metadata_key(std::string_view topic_name,
-                                   std::string_view tenant);
+std::string get_topic_metadata_key(std::string_view tenant,
+                                   std::string_view topic_name);
+std::string get_topic_metadata_key(const rgw_pubsub_topic& topic);
 void parse_topic_metadata_key(const std::string& key,
                               std::string& tenant_name,
                               std::string& topic_name);
index 27fad86a58b0180814a3c2bbb67edd9038977e49..4fb1051ebf6bc3794ffb421944cd6b9be4a24207 100644 (file)
@@ -106,7 +106,7 @@ int verify_topic_owner_or_policy(req_state* const s,
                                  const rgw_pubsub_topic& topic,
                                  const std::string& zonegroup_name,
                                  const uint64_t op) {
-  if (topic.user == s->owner.id) {
+  if (s->auth.identity->is_owner_of(topic.owner)) {
     return 0;
   }
   // no policy set.
@@ -115,7 +115,7 @@ int verify_topic_owner_or_policy(req_state* const s,
     if (op == rgw::IAM::snsPublish && !s->cct->_conf->rgw_topic_require_publish_policy) {
       return 0;
     }
-    if (topic.user.empty()) {
+    if (std::visit([] (const auto& o) { return o.empty(); }, topic.owner)) {
       // if we don't know the original user and there is no policy
       // we will not reject the request.
       // this is for compatibility with versions that did not store the user in the topic
@@ -563,7 +563,7 @@ class RGWPSSetTopicAttributesOp : public RGWOp {
   std::string opaque_data;
   std::string policy_text;
   rgw_pubsub_dest dest;
-  rgw_user topic_owner;
+  rgw_owner topic_owner;
   std::string attribute_name;
 
   int get_params() {
@@ -669,7 +669,7 @@ class RGWPSSetTopicAttributesOp : public RGWOp {
                          << "', ret=" << ret << dendl;
       return ret;
     }
-    topic_owner = result.user;
+    topic_owner = result.owner;
     ret = verify_topic_owner_or_policy(
         s, result, driver->get_zone()->get_zonegroup().get_name(),
         rgw::IAM::snsSetTopicAttributes);
index 25770487ccaca3d845b1ae9dd53d9ef58a39536c..df69fbaf05957ef9c53147bb54a37c92ad8153b6 100644 (file)
@@ -621,7 +621,7 @@ def test_ps_s3_topic_admin_on_master():
     parsed_result = json.loads(result[0])
     assert_equal(parsed_result['arn'], topic_arn3)
     matches = [tenant, UID_PREFIX]
-    assert_true( all([x in parsed_result['user'] for x in matches]))
+    assert_true( all([x in parsed_result['owner'] for x in matches]))
 
     # delete topic 3
     _, result = admin(['topic', 'rm', '--topic', topic_name+'_3', '--tenant', tenant], get_config_cluster())