driver/rados/account.cc
driver/rados/buckets.cc
driver/rados/cls_fifo_legacy.cc
+ driver/rados/group.cc
+ driver/rados/groups.cc
driver/rados/rgw_bucket.cc
driver/rados/rgw_bucket_sync.cc
driver/rados/rgw_cr_rados.cc
static constexpr std::string_view buckets_oid_prefix = "buckets.";
static constexpr std::string_view users_oid_prefix = "users.";
+static constexpr std::string_view groups_oid_prefix = "groups.";
static constexpr std::string_view roles_oid_prefix = "roles.";
static const std::string account_oid_prefix = "account.";
static constexpr std::string_view name_oid_prefix = "name.";
return {zone.account_pool, get_users_key(account_id)};
}
+static std::string get_groups_key(std::string_view account_id) {
+ return string_cat_reserve(groups_oid_prefix, account_id);
+}
+rgw_raw_obj get_groups_obj(const RGWZoneParams& zone,
+ std::string_view account_id) {
+ return {zone.account_pool, get_groups_key(account_id)};
+}
+
static std::string get_roles_key(std::string_view account_id) {
return string_cat_reserve(roles_oid_prefix, account_id);
}
rgw_raw_obj get_users_obj(const RGWZoneParams& zone,
std::string_view account_id);
+/// Return the rados object that tracks the given account's groups. This
+/// can be used with the cls_user interface in namespace rgwrados::groups.
+rgw_raw_obj get_groups_obj(const RGWZoneParams& zone,
+ std::string_view account_id);
+
/// Return the rados object that tracks the given account's roles. This
/// can be used with the cls_user interface in namespace rgwrados::roles.
rgw_raw_obj get_roles_obj(const RGWZoneParams& zone,
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab ft=cpp
+
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright contributors to the Ceph project
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation. See file COPYING.
+ *
+ */
+
+#include "group.h"
+
+#include <boost/algorithm/string.hpp>
+#include "common/errno.h"
+#include "account.h"
+#include "groups.h"
+#include "rgw_common.h"
+#include "rgw_metadata.h"
+#include "rgw_metadata_lister.h"
+#include "rgw_obj_types.h"
+#include "rgw_string.h"
+#include "rgw_tools.h"
+#include "rgw_user.h"
+#include "rgw_zone.h"
+#include "services/svc_sys_obj.h"
+
+namespace rgwrados::group {
+
+static constexpr std::string_view info_oid_prefix = "info.";
+static constexpr std::string_view name_oid_prefix = "name.";
+static constexpr std::string_view users_oid_prefix = "users.";
+
+// metadata keys/objects
+std::string get_users_key(std::string_view group_id) {
+ return string_cat_reserve(users_oid_prefix, group_id);
+}
+rgw_raw_obj get_users_obj(const RGWZoneParams& zone,
+ std::string_view group_id) {
+ return {zone.group_pool, get_users_key(group_id)};
+}
+
+static std::string get_group_key(std::string_view group_id) {
+ return string_cat_reserve(info_oid_prefix, group_id);
+}
+static rgw_raw_obj get_group_obj(const RGWZoneParams& zone,
+ std::string_view group_id) {
+ return {zone.group_pool, get_group_key(group_id)};
+}
+
+static std::string get_name_key(std::string_view account,
+ std::string_view name) {
+ // names are case-insensitive, so store them in lower case
+ std::string lower_name{name};
+ boost::algorithm::to_lower(lower_name);
+ return string_cat_reserve(name_oid_prefix, account, "$", lower_name);
+}
+static rgw_raw_obj get_name_obj(const RGWZoneParams& zone,
+ std::string_view account,
+ std::string_view name) {
+ return {zone.group_pool, get_name_key(account, name)};
+}
+
+
+struct NameObj {
+ rgw_raw_obj obj;
+ RGWUID data;
+ RGWObjVersionTracker objv;
+};
+
+static int read_name(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ RGWSI_SysObj& sysobj,
+ NameObj& name)
+{
+ bufferlist bl;
+ int r = rgw_get_system_obj(&sysobj, name.obj.pool, name.obj.oid,
+ bl, &name.objv, nullptr, y, dpp);
+ if (r < 0) {
+ ldpp_dout(dpp, 20) << "failed to read " << name.obj.oid
+ << " with: " << cpp_strerror(r) << dendl;
+ return r;
+ }
+
+ try {
+ auto p = bl.cbegin();
+ decode(name.data, p);
+ } catch (const buffer::error& e) {
+ ldpp_dout(dpp, 0) << "ERROR: failed to decode group name: "
+ << e.what() << dendl;
+ return -EIO;
+ }
+ return 0;
+}
+
+static int write_name(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ RGWSI_SysObj& sysobj,
+ NameObj& name)
+{
+ bufferlist bl;
+ encode(name.data, bl);
+
+ constexpr bool exclusive = true;
+ return rgw_put_system_obj(dpp, &sysobj, name.obj.pool,
+ name.obj.oid, bl, exclusive,
+ &name.objv, ceph::real_time{}, y);
+}
+
+
+int read(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ RGWSI_SysObj& sysobj,
+ const RGWZoneParams& zone,
+ std::string_view id,
+ RGWGroupInfo& info,
+ std::map<std::string, ceph::buffer::list>& attrs,
+ ceph::real_time& mtime,
+ RGWObjVersionTracker& objv)
+{
+ const rgw_raw_obj obj = get_group_obj(zone, id);
+
+ bufferlist bl;
+ int r = rgw_get_system_obj(&sysobj, obj.pool, obj.oid, bl,
+ &objv, &mtime, y, dpp, &attrs);
+ if (r < 0) {
+ ldpp_dout(dpp, 20) << "group lookup with id=" << id
+ << " failed: " << cpp_strerror(r) << dendl;
+ return r;
+ }
+
+ try {
+ auto p = bl.cbegin();
+ decode(info, p);
+ } catch (const buffer::error& e) {
+ ldpp_dout(dpp, 0) << "ERROR: failed to decode group info: "
+ << e.what() << dendl;
+ return -EIO;
+ }
+ if (info.id != id) {
+ ldpp_dout(dpp, 0) << "ERROR: read group id mismatch "
+ << info.id << " != " << id << dendl;
+ return -EIO;
+ }
+ return 0;
+}
+
+int read_by_name(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ RGWSI_SysObj& sysobj,
+ const RGWZoneParams& zone,
+ std::string_view tenant,
+ std::string_view name,
+ RGWGroupInfo& info,
+ std::map<std::string, ceph::buffer::list>& attrs,
+ RGWObjVersionTracker& objv)
+{
+ auto nameobj = NameObj{.obj = get_name_obj(zone, tenant, name)};
+ int r = read_name(dpp, y, sysobj, nameobj);
+ if (r < 0) {
+ return r;
+ }
+ ceph::real_time mtime; // ignored
+ return read(dpp, y, sysobj, zone, nameobj.data.id, info, attrs, mtime, objv);
+}
+
+
+int write(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ RGWSI_SysObj& sysobj,
+ librados::Rados& rados,
+ const RGWZoneParams& zone,
+ const RGWGroupInfo& info,
+ const RGWGroupInfo* old_info,
+ const std::map<std::string, ceph::buffer::list>& attrs,
+ ceph::real_time mtime,
+ bool exclusive,
+ RGWObjVersionTracker& objv)
+{
+ const rgw_raw_obj obj = get_group_obj(zone, info.id);
+
+ const bool same_name = old_info
+ && old_info->account_id == info.account_id
+ && old_info->name == info.name;
+
+ std::optional<NameObj> remove_name;
+ if (old_info) {
+ if (old_info->id != info.id) {
+ ldpp_dout(dpp, 1) << "ERROR: can't modify group id" << dendl;
+ return -EINVAL;
+ }
+ if (!same_name && !old_info->name.empty()) {
+ // read old group name object
+ NameObj nameobj;
+ nameobj.obj = get_name_obj(zone, old_info->account_id, old_info->name);
+ int r = read_name(dpp, y, sysobj, nameobj);
+ if (r == -ENOENT) {
+ // leave remove_name empty
+ } else if (r < 0) {
+ return r;
+ } else if (nameobj.data.id == info.id) {
+ remove_name = std::move(nameobj);
+ }
+ }
+ } // old_info
+
+ if (!same_name && !info.name.empty()) {
+ // read new account name object
+ NameObj nameobj;
+ nameobj.obj = get_name_obj(zone, info.account_id, info.name);
+ int r = read_name(dpp, y, sysobj, nameobj);
+ if (r == -ENOENT) {
+ // write the new name object below
+ } else if (r == 0) {
+ ldpp_dout(dpp, 1) << "ERROR: group name obj " << nameobj.obj
+ << " already taken for group id " << nameobj.data.id << dendl;
+ return -EEXIST;
+ } else if (r < 0) {
+ return r;
+ }
+ }
+
+ // encode/write the group info
+ {
+ bufferlist bl;
+ encode(info, bl);
+
+ const rgw_raw_obj obj = get_group_obj(zone, info.id);
+ int r = rgw_put_system_obj(dpp, &sysobj, obj.pool, obj.oid, bl,
+ exclusive, &objv, mtime, y, &attrs);
+ if (r < 0) {
+ ldpp_dout(dpp, 1) << "ERROR: failed to write group obj " << obj
+ << " with: " << cpp_strerror(r) << dendl;
+ return r;
+ }
+ }
+
+ if (remove_name) {
+ // remove the old name object, ignoring errors
+ auto& nameobj = *remove_name;
+ int r = rgw_delete_system_obj(dpp, &sysobj, nameobj.obj.pool,
+ nameobj.obj.oid, &nameobj.objv, y);
+ if (r < 0) {
+ ldpp_dout(dpp, 20) << "WARNING: failed to remove old name obj "
+ << nameobj.obj.oid << ": " << cpp_strerror(r) << dendl;
+ } // not fatal
+ // unlink the old name from its account
+ const auto& users = account::get_groups_obj(zone, old_info->account_id);
+ r = groups::remove(dpp, y, rados, users, old_info->name);
+ if (r < 0) {
+ ldpp_dout(dpp, 0) << "ERROR: could not unlink from account "
+ << old_info->account_id << ": " << cpp_strerror(r) << dendl;
+ } // not fatal
+ }
+ if (!same_name && !info.name.empty()) {
+ // write the new name object
+ NameObj nameobj;
+ nameobj.obj = get_name_obj(zone, info.account_id, info.name);
+ nameobj.data.id = info.id;
+ nameobj.objv.generate_new_write_ver(dpp->get_cct());
+
+ int r = write_name(dpp, y, sysobj, nameobj);
+ if (r < 0) {
+ ldpp_dout(dpp, 20) << "WARNING: failed to write name obj "
+ << nameobj.obj << " with: " << cpp_strerror(r) << dendl;
+ } // not fatal
+ // link the new name to its account
+ const auto& users = account::get_groups_obj(zone, info.account_id);
+ r = groups::add(dpp, y, rados, users, info, false,
+ std::numeric_limits<uint32_t>::max());
+ if (r < 0) {
+ ldpp_dout(dpp, 0) << "ERROR: could not link to account "
+ << info.account_id << ": " << cpp_strerror(r) << dendl;
+ } // not fatal
+ }
+
+ return 0;
+}
+
+int remove(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ RGWSI_SysObj& sysobj,
+ librados::Rados& rados,
+ const RGWZoneParams& zone,
+ const RGWGroupInfo& info,
+ RGWObjVersionTracker& objv)
+{
+ const rgw_raw_obj obj = get_group_obj(zone, info.id);
+ int r = rgw_delete_system_obj(dpp, &sysobj, obj.pool, obj.oid, &objv, y);
+ if (r < 0) {
+ ldpp_dout(dpp, 1) << "ERROR: failed to remove account obj "
+ << obj << " with: " << cpp_strerror(r) << dendl;
+ return r;
+ }
+
+ {
+ // remove the name object
+ const rgw_raw_obj obj = get_name_obj(zone, info.account_id, info.name);
+ r = rgw_delete_system_obj(dpp, &sysobj, obj.pool, obj.oid, nullptr, y);
+ if (r < 0) {
+ ldpp_dout(dpp, 20) << "WARNING: failed to remove name obj "
+ << obj << " with: " << cpp_strerror(r) << dendl;
+ } // not fatal
+ }
+ {
+ // remove the users object
+ const rgw_raw_obj obj = get_users_obj(zone, info.id);
+ r = rgw_delete_system_obj(dpp, &sysobj, obj.pool, obj.oid, nullptr, y);
+ if (r < 0) {
+ ldpp_dout(dpp, 20) << "WARNING: failed to remove users obj "
+ << obj << " with: " << cpp_strerror(r) << dendl;
+ } // not fatal
+ }
+ {
+ // unlink the name from its account
+ const auto& users = account::get_groups_obj(zone, info.account_id);
+ r = groups::remove(dpp, y, rados, users, info.name);
+ if (r < 0) {
+ ldpp_dout(dpp, 0) << "ERROR: could not unlink from account "
+ << info.account_id << ": " << cpp_strerror(r) << dendl;
+ } // not fatal
+ }
+
+ return 0;
+}
+
+
+// metadata abstraction
+
+struct CompleteInfo {
+ RGWGroupInfo info;
+ std::map<std::string, bufferlist> attrs;
+ bool has_attrs = false;
+
+ void dump(Formatter* f) const {
+ info.dump(f);
+ encode_json("attrs", attrs, f);
+ }
+
+ void decode_json(JSONObj* obj) {
+ decode_json_obj(info, obj);
+ has_attrs = JSONDecoder::decode_json("attrs", attrs, obj);
+ }
+};
+
+class MetadataObject : public RGWMetadataObject {
+ CompleteInfo aci;
+ public:
+ MetadataObject(CompleteInfo& aci, const obj_version& v, ceph::real_time m)
+ : RGWMetadataObject(v, m), aci(std::move(aci)) {}
+
+ void dump(Formatter *f) const override {
+ aci.dump(f);
+ }
+
+ CompleteInfo& get() { return aci; }
+};
+
+class MetadataLister : public RGWMetadataLister {
+ public:
+ using RGWMetadataLister::RGWMetadataLister;
+
+ void filter_transform(std::vector<std::string>& oids,
+ std::list<std::string>& keys) override
+ {
+ // remove the oid prefix from keys
+ constexpr auto trim = [] (const std::string& oid) {
+ return oid.substr(info_oid_prefix.size());
+ };
+ std::transform(oids.begin(), oids.end(),
+ std::back_inserter(keys),
+ trim);
+ }
+};
+
+class MetadataHandler : public RGWMetadataHandler {
+ RGWSI_SysObj& sysobj;
+ librados::Rados& rados;
+ const RGWZoneParams& zone;
+ public:
+ MetadataHandler(RGWSI_SysObj& sysobj, librados::Rados& rados,
+ const RGWZoneParams& zone)
+ : sysobj(sysobj), rados(rados), zone(zone) {}
+
+ std::string get_type() override { return "group"; }
+
+ RGWMetadataObject* get_meta_obj(JSONObj* obj,
+ const obj_version& objv,
+ const ceph::real_time& mtime) override
+ {
+ CompleteInfo aci;
+ try {
+ decode_json_obj(aci, obj);
+ } catch (const JSONDecoder::err&) {
+ return nullptr;
+ }
+ return new MetadataObject(aci, objv, mtime);
+ }
+
+ int get(std::string& entry, RGWMetadataObject** obj,
+ optional_yield y, const DoutPrefixProvider* dpp) override
+ {
+ const std::string& group_id = entry;
+ CompleteInfo aci;
+ RGWObjVersionTracker objv;
+ ceph::real_time mtime;
+
+ int r = read(dpp, y, sysobj, zone, group_id,
+ aci.info, aci.attrs, mtime, objv);
+ if (r < 0) {
+ return r;
+ }
+
+ *obj = new MetadataObject(aci, objv.read_version, mtime);
+ return 0;
+ }
+
+ int put(std::string& entry, RGWMetadataObject* obj,
+ RGWObjVersionTracker& objv, optional_yield y,
+ const DoutPrefixProvider* dpp,
+ RGWMDLogSyncType type, bool from_remote_zone) override
+ {
+ const std::string& group_id = entry;
+ auto group_obj = static_cast<MetadataObject*>(obj);
+ const auto& new_info = group_obj->get().info;
+
+ // account id must match metadata key
+ if (new_info.id != group_id) {
+ return -EINVAL;
+ }
+
+ // read existing metadata
+ RGWGroupInfo old_info;
+ std::map<std::string, ceph::buffer::list> old_attrs;
+ ceph::real_time old_mtime;
+ int r = read(dpp, y, sysobj, zone, group_id,
+ old_info, old_attrs, old_mtime, objv);
+ if (r < 0 && r != -ENOENT) {
+ return r;
+ }
+ const RGWGroupInfo* pold_info = (r == -ENOENT ? nullptr : &old_info);
+
+ // write/overwrite metadata
+ constexpr bool exclusive = false;
+ return write(dpp, y, sysobj, rados, zone, new_info, pold_info,
+ group_obj->get().attrs, obj->get_mtime(),
+ exclusive, objv);
+ }
+
+ int remove(std::string& entry, RGWObjVersionTracker& objv,
+ optional_yield y, const DoutPrefixProvider* dpp) override
+ {
+ const std::string& group_id = entry;
+
+ // read existing metadata
+ RGWGroupInfo info;
+ std::map<std::string, ceph::buffer::list> attrs;
+ ceph::real_time mtime;
+ int r = read(dpp, y, sysobj, zone, group_id,
+ info, attrs, mtime, objv);
+ if (r < 0) {
+ return r;
+ }
+
+ return group::remove(dpp, y, sysobj, rados, zone, info, objv);
+ }
+
+ int mutate(const std::string& entry,
+ const ceph::real_time& mtime,
+ RGWObjVersionTracker* objv,
+ optional_yield y,
+ const DoutPrefixProvider* dpp,
+ RGWMDLogStatus op_type,
+ std::function<int()> f) override
+ {
+ return -ENOTSUP; // unused
+ }
+
+ int list_keys_init(const DoutPrefixProvider* dpp,
+ const std::string& marker, void** phandle) override
+ {
+ auto lister = std::make_unique<MetadataLister>(
+ sysobj.get_pool(zone.group_pool));
+ int r = lister->init(dpp, marker, std::string{info_oid_prefix});
+ if (r < 0) {
+ return r;
+ }
+ *phandle = lister.release();
+ return 0;
+ }
+
+ int list_keys_next(const DoutPrefixProvider* dpp, void* handle, int max,
+ std::list<std::string>& keys, bool* truncated) override
+ {
+ auto lister = static_cast<MetadataLister*>(handle);
+ return lister->get_next(dpp, max, keys, truncated);
+ }
+
+ void list_keys_complete(void* handle) override
+ {
+ delete static_cast<MetadataLister*>(handle);
+ }
+
+ std::string get_marker(void* handle) override
+ {
+ auto lister = static_cast<MetadataLister*>(handle);
+ return lister->get_marker();
+ }
+};
+
+auto create_metadata_handler(RGWSI_SysObj& sysobj, librados::Rados& rados,
+ const RGWZoneParams& zone)
+ -> std::unique_ptr<RGWMetadataHandler>
+{
+ return std::make_unique<MetadataHandler>(sysobj, rados, zone);
+}
+
+} // namespace rgwrados::group
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab ft=cpp
+
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright contributors to the Ceph project
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation. See file COPYING.
+ *
+ */
+
+#pragma once
+
+#include <map>
+#include <memory>
+#include <string>
+#include "include/buffer_fwd.h"
+#include "include/rados/librados_fwd.hpp"
+#include "common/async/yield_context.h"
+#include "common/ceph_time.h"
+
+class DoutPrefixProvider;
+struct rgw_raw_obj;
+class RGWGroupInfo;
+class RGWMetadataHandler;
+class RGWObjVersionTracker;
+class RGWSI_SysObj;
+class RGWZoneParams;
+
+namespace rgwrados::group {
+
+/// Group metadata handler factory
+auto create_metadata_handler(RGWSI_SysObj& sysobj, librados::Rados& rados,
+ const RGWZoneParams& zone)
+ -> std::unique_ptr<RGWMetadataHandler>;
+
+/// Return the rados object that tracks the given group's users
+rgw_raw_obj get_users_obj(const RGWZoneParams& zone,
+ std::string_view group_id);
+
+
+/// Read group info by id
+int read(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ RGWSI_SysObj& sysobj,
+ const RGWZoneParams& zone,
+ std::string_view id,
+ RGWGroupInfo& info,
+ std::map<std::string, ceph::buffer::list>& attrs,
+ ceph::real_time& mtime,
+ RGWObjVersionTracker& objv);
+
+/// Read group info by name
+int read_by_name(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ RGWSI_SysObj& sysobj,
+ const RGWZoneParams& zone,
+ std::string_view account_id,
+ std::string_view name,
+ RGWGroupInfo& info,
+ std::map<std::string, ceph::buffer::list>& attrs,
+ RGWObjVersionTracker& objv);
+
+/// Write group info and update name index
+int write(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ RGWSI_SysObj& sysobj,
+ librados::Rados& rados,
+ const RGWZoneParams& zone,
+ const RGWGroupInfo& info,
+ const RGWGroupInfo* old_info,
+ const std::map<std::string, ceph::buffer::list>& attrs,
+ ceph::real_time mtime,
+ bool exclusive,
+ RGWObjVersionTracker& objv);
+
+/// Remove group info and name index
+int remove(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ RGWSI_SysObj& sysobj,
+ librados::Rados& rados,
+ const RGWZoneParams& zone,
+ const RGWGroupInfo& info,
+ RGWObjVersionTracker& objv);
+
+} // namespace rgwrados::group
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab ft=cpp
+
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright contributors to the Ceph project
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation. See file COPYING.
+ *
+ */
+
+#include "groups.h"
+
+#include "include/rados/librados.hpp"
+#include "common/ceph_json.h"
+#include "common/dout.h"
+#include "cls/user/cls_user_client.h"
+#include "rgw_sal.h"
+
+namespace rgwrados::groups {
+
+int add(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ librados::Rados& rados,
+ const rgw_raw_obj& obj,
+ const RGWGroupInfo& group,
+ bool exclusive, uint32_t limit)
+{
+ resource_metadata meta;
+ meta.group_id = group.id;
+
+ cls_user_account_resource resource;
+ resource.name = group.name;
+ resource.path = group.path;
+ encode(meta, resource.metadata);
+
+ rgw_rados_ref ref;
+ int r = rgw_get_rados_ref(dpp, &rados, obj, &ref);
+ if (r < 0) {
+ return r;
+ }
+
+ librados::ObjectWriteOperation op;
+ ::cls_user_account_resource_add(op, resource, exclusive, limit);
+ return ref.operate(dpp, &op, y);
+}
+
+int remove(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ librados::Rados& rados,
+ const rgw_raw_obj& obj,
+ std::string_view name)
+{
+ rgw_rados_ref ref;
+ int r = rgw_get_rados_ref(dpp, &rados, obj, &ref);
+ if (r < 0) {
+ return r;
+ }
+
+ librados::ObjectWriteOperation op;
+ ::cls_user_account_resource_rm(op, name);
+ return ref.operate(dpp, &op, y);
+}
+
+int list(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ librados::Rados& rados,
+ const rgw_raw_obj& obj,
+ std::string_view marker,
+ std::string_view path_prefix,
+ uint32_t max_items,
+ std::vector<std::string>& ids,
+ std::string& next_marker)
+{
+ rgw_rados_ref ref;
+ int r = rgw_get_rados_ref(dpp, &rados, obj, &ref);
+ if (r < 0) {
+ return r;
+ }
+
+ librados::ObjectReadOperation op;
+ std::vector<cls_user_account_resource> entries;
+ bool truncated = false;
+ int ret = 0;
+ ::cls_user_account_resource_list(op, marker, path_prefix, max_items,
+ entries, &truncated, &next_marker, &ret);
+
+ r = ref.operate(dpp, &op, nullptr, y);
+ if (r == -ENOENT) {
+ next_marker.clear();
+ return 0;
+ }
+ if (r < 0) {
+ return r;
+ }
+ if (ret < 0) {
+ return ret;
+ }
+
+ for (auto& resource : entries) {
+ resource_metadata meta;
+ try {
+ auto p = resource.metadata.cbegin();
+ decode(meta, p);
+ } catch (const buffer::error&) {
+ return -EIO;
+ }
+ ids.push_back(std::move(meta.group_id));
+ }
+
+ if (!truncated) {
+ next_marker.clear();
+ }
+ return 0;
+}
+
+
+void resource_metadata::dump(ceph::Formatter* f) const
+{
+ encode_json("group_id", group_id, f);
+}
+
+void resource_metadata::generate_test_instances(std::list<resource_metadata*>& o)
+{
+ o.push_back(new resource_metadata);
+ auto m = new resource_metadata;
+ m->group_id = "id";
+ o.push_back(m);
+}
+
+} // namespace rgwrados::groups
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab ft=cpp
+
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright contributors to the Ceph project
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation. See file COPYING.
+ *
+ */
+
+#pragma once
+
+#include <list>
+#include <string>
+#include "include/rados/librados_fwd.hpp"
+#include "include/encoding.h"
+#include "rgw_sal_fwd.h"
+
+namespace ceph { class Formatter; }
+class DoutPrefixProvider;
+class optional_yield;
+struct rgw_raw_obj;
+struct RGWGroupInfo;
+
+
+namespace rgwrados::groups {
+
+/// Add the given group to the list.
+int add(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ librados::Rados& rados,
+ const rgw_raw_obj& obj,
+ const RGWGroupInfo& info,
+ bool exclusive, uint32_t limit);
+
+/// Remove the given group from the list.
+int remove(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ librados::Rados& rados,
+ const rgw_raw_obj& obj,
+ std::string_view name);
+
+/// Return a paginated listing of group ids.
+int list(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ librados::Rados& rados,
+ const rgw_raw_obj& obj,
+ std::string_view marker,
+ std::string_view path_prefix,
+ uint32_t max_items,
+ std::vector<std::string>& ids,
+ std::string& next_marker);
+
+// group-specific metadata for cls_user_account_resource
+struct resource_metadata {
+ std::string group_id;
+
+ void encode(bufferlist& bl) const {
+ ENCODE_START(1, 1, bl);
+ encode(group_id, bl);
+ ENCODE_FINISH(bl);
+ }
+ void decode(bufferlist::const_iterator& bl) {
+ DECODE_START(1, bl);
+ decode(group_id, bl);
+ DECODE_FINISH(bl);
+ }
+
+ void dump(ceph::Formatter* f) const;
+ static void generate_test_instances(std::list<resource_metadata*>& o);
+};
+WRITE_CLASS_ENCODER(resource_metadata);
+
+} // namespace rgwrados::groups
#include "account.h"
#include "buckets.h"
+#include "group.h"
+#include "groups.h"
#include "roles.h"
#include "users.h"
#include "rgw_pubsub.h"
return 0;
}
+int RadosUser::list_groups(const DoutPrefixProvider* dpp, optional_yield y,
+ std::string_view marker, uint32_t max_items,
+ GroupList& listing)
+{
+ RGWSI_SysObj& sysobj = *store->svc()->sysobj;
+ const RGWZoneParams& zone = store->svc()->zone->get_zone_params();
+
+ const auto& ids = info.group_ids;
+ for (auto id = ids.lower_bound(marker); id != ids.end(); ++id) {
+ if (listing.groups.size() >= max_items) {
+ listing.next_marker = *id;
+ return 0;
+ }
+
+ RGWGroupInfo info;
+ Attrs attrs_ignored;
+ ceph::real_time mtime_ignored;
+ RGWObjVersionTracker objv_ignored;
+ int r = rgwrados::group::read(dpp, y, sysobj, zone, *id, info,
+ attrs_ignored, mtime_ignored, objv_ignored);
+ if (r == -ENOENT) {
+ continue;
+ }
+ if (r < 0) {
+ return r;
+ }
+ listing.groups.push_back(std::move(info));
+ }
+
+ listing.next_marker.clear();
+ return 0;
+}
+
RadosBucket::~RadosBucket() {}
int RadosBucket::remove(const DoutPrefixProvider* dpp,
return 0;
}
+int RadosStore::load_group_by_id(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view id,
+ RGWGroupInfo& info, Attrs& attrs,
+ RGWObjVersionTracker& objv)
+{
+ const RGWZoneParams& zone = svc()->zone->get_zone_params();
+ ceph::real_time mtime_ignored;
+ return rgwrados::group::read(dpp, y, *svc()->sysobj, zone, id,
+ info, attrs, mtime_ignored, objv);
+}
+
+int RadosStore::load_group_by_name(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view account_id,
+ std::string_view name,
+ RGWGroupInfo& info, Attrs& attrs,
+ RGWObjVersionTracker& objv)
+{
+ const RGWZoneParams& zone = svc()->zone->get_zone_params();
+ return rgwrados::group::read_by_name(dpp, y, *svc()->sysobj, zone, account_id,
+ name, info, attrs, objv);
+}
+
+int RadosStore::store_group(const DoutPrefixProvider* dpp, optional_yield y,
+ const RGWGroupInfo& info, const Attrs& attrs,
+ RGWObjVersionTracker& objv, bool exclusive,
+ const RGWGroupInfo* old_info)
+{
+ librados::Rados& rados = *getRados()->get_rados_handle();
+ const RGWZoneParams& zone = svc()->zone->get_zone_params();
+ ceph::real_time mtime = ceph::real_clock::now();
+ int r = rgwrados::group::write(dpp, y, *svc()->sysobj, rados, zone, info,
+ old_info, attrs, mtime, exclusive, objv);
+ if (r < 0) {
+ return r;
+ }
+
+ return write_mdlog_entry(dpp, y, *svc()->mdlog, "group", info.id, objv);
+}
+
+int RadosStore::remove_group(const DoutPrefixProvider* dpp, optional_yield y,
+ const RGWGroupInfo& info,
+ RGWObjVersionTracker& objv)
+{
+ librados::Rados& rados = *getRados()->get_rados_handle();
+ const RGWZoneParams& zone = svc()->zone->get_zone_params();
+ int r = rgwrados::group::remove(dpp, y, *svc()->sysobj, rados, zone, info, objv);
+ if (r < 0) {
+ return r;
+ }
+
+ return write_mdlog_entry(dpp, y, *svc()->mdlog, "group", info.id, objv);
+}
+
+int RadosStore::list_group_users(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view tenant,
+ std::string_view id,
+ std::string_view marker,
+ uint32_t max_items,
+ UserList& listing)
+{
+ // fetch the list of user ids from cls_user
+ librados::Rados& rados = *getRados()->get_rados_handle();
+ const RGWZoneParams& zone = svc()->zone->get_zone_params();
+ const rgw_raw_obj& obj = rgwrados::group::get_users_obj(zone, id);
+ const std::string path_prefix; // empty
+ std::vector<std::string> ids;
+ int r = rgwrados::users::list(dpp, y, rados, obj, marker, path_prefix,
+ max_items, ids, listing.next_marker);
+ if (r < 0) {
+ return r;
+ }
+
+ // load the user metadata for each
+ for (auto& id : ids) {
+ rgw_user uid;
+ uid.tenant = tenant;
+ uid.id = std::move(id);
+
+ RGWUserInfo info;
+ r = ctl()->user->get_info_by_uid(dpp, uid, &info, y);
+ if (r == -ENOENT) {
+ continue;
+ }
+ if (r < 0) {
+ return r;
+ }
+ listing.users.push_back(std::move(info));
+ }
+
+ return 0;
+}
+
+int RadosStore::count_account_groups(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view account_id,
+ uint32_t& count)
+{
+ librados::Rados& rados = *getRados()->get_rados_handle();
+ const RGWZoneParams& zone = svc()->zone->get_zone_params();
+ const rgw_raw_obj& obj = rgwrados::account::get_groups_obj(zone, account_id);
+ return rgwrados::account::resource_count(dpp, y, rados, obj, count);
+}
+
+int RadosStore::list_account_groups(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view account_id,
+ std::string_view path_prefix,
+ std::string_view marker,
+ uint32_t max_items,
+ GroupList& listing)
+{
+ // fetch the list of group ids from cls_user
+ librados::Rados& rados = *getRados()->get_rados_handle();
+ const RGWZoneParams& zone = svc()->zone->get_zone_params();
+ const rgw_raw_obj& obj = rgwrados::account::get_groups_obj(zone, account_id);
+ std::vector<std::string> ids;
+ int r = rgwrados::groups::list(dpp, y, rados, obj, marker, path_prefix,
+ max_items, ids, listing.next_marker);
+ if (r < 0) {
+ return r;
+ }
+
+ // load the group metadata for each
+ for (auto& id : ids) {
+ RGWGroupInfo info;
+ Attrs attrs;
+ ceph::real_time mtime_ignored;
+ RGWObjVersionTracker objv;
+ r = rgwrados::group::read(dpp, y, *svc()->sysobj, zone, id,
+ info, attrs, mtime_ignored, objv);
+ if (r == -ENOENT) {
+ continue;
+ }
+ if (r < 0) {
+ return r;
+ }
+ listing.groups.push_back(std::move(info));
+ }
+
+ return 0;
+}
+
std::unique_ptr<Object> RadosStore::get_object(const rgw_obj_key& k)
{
return std::make_unique<RadosObject>(this, k);
uint32_t max_items,
UserList& listing) override;
+ int load_group_by_id(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view id,
+ RGWGroupInfo& info, Attrs& attrs,
+ RGWObjVersionTracker& objv) override;
+ int load_group_by_name(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view account_id,
+ std::string_view name,
+ RGWGroupInfo& info, Attrs& attrs,
+ RGWObjVersionTracker& objv) override;
+ int store_group(const DoutPrefixProvider* dpp, optional_yield y,
+ const RGWGroupInfo& info, const Attrs& attrs,
+ RGWObjVersionTracker& objv, bool exclusive,
+ const RGWGroupInfo* old_info) override;
+ int remove_group(const DoutPrefixProvider* dpp, optional_yield y,
+ const RGWGroupInfo& info,
+ RGWObjVersionTracker& objv) override;
+ int list_group_users(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view tenant,
+ std::string_view id,
+ std::string_view marker,
+ uint32_t max_items,
+ UserList& listing) override;
+ int count_account_groups(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view account_id,
+ uint32_t& count) override;
+ int list_account_groups(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view account_id,
+ std::string_view path_prefix,
+ std::string_view marker,
+ uint32_t max_items,
+ GroupList& listing) override;
+
virtual std::unique_ptr<Object> get_object(const rgw_obj_key& k) override;
std::unique_ptr<Bucket> get_bucket(const RGWBucketInfo& i) override;
int load_bucket(const DoutPrefixProvider* dpp, const rgw_bucket& b,
virtual int store_user(const DoutPrefixProvider* dpp, optional_yield y, bool exclusive, RGWUserInfo* old_info = nullptr) override;
virtual int remove_user(const DoutPrefixProvider* dpp, optional_yield y) override;
virtual int verify_mfa(const std::string& mfa_str, bool* verified, const DoutPrefixProvider* dpp, optional_yield y) override;
+ int list_groups(const DoutPrefixProvider* dpp, optional_yield y,
+ std::string_view marker, uint32_t max_items,
+ GroupList& listing) override;
friend class RadosBucket;
};
#include "common/errno.h"
#include "account.h"
+#include "group.h"
#include "rgw_bucket.h"
#include "rgw_cr_rados.h"
#include "rgw_datalog.h"
meta.role = std::make_unique<rgw::sal::RGWRoleMetadataHandler>(driver, svc.role);
meta.account = rgwrados::account::create_metadata_handler(
*svc.sysobj, svc.zone->get_zone_params());
+ meta.group = rgwrados::group::create_metadata_handler(
+ *svc.sysobj, rados, svc.zone->get_zone_params());
user.reset(new RGWUserCtl(svc.zone, svc.user, (RGWUserMetadataHandler *)meta.user.get()));
bucket.reset(new RGWBucketCtl(svc.zone,
ldout(cct, 0) << "ERROR: failed to start init meta.account ctl (" << cpp_strerror(-r) << dendl;
return r;
}
+
r = meta.topic->attach(meta.mgr);
if (r < 0) {
ldout(cct, 0) << "ERROR: failed to start init topic ctl ("
<< cpp_strerror(-r) << dendl;
return r;
}
+
+ r = _ctl.meta.group->attach(meta.mgr);
+ if (r < 0) {
+ ldout(cct, 0) << "ERROR: failed to start init meta.group ctl (" << cpp_strerror(-r) << dendl;
+ return r;
+ }
return 0;
}
std::unique_ptr<RGWMetadataHandler> role;
std::unique_ptr<RGWMetadataHandler> topic;
std::unique_ptr<RGWMetadataHandler> account;
+ std::unique_ptr<RGWMetadataHandler> group;
std::unique_ptr<RGWChainedCacheImpl<rgwrados::topic::cache_entry>> topic_cache;
rgw_pool notif_pool;
rgw_pool topics_pool;
rgw_pool account_pool;
+ rgw_pool group_pool;
RGWAccessKey system_key;
encode(notif_pool, bl);
encode(topics_pool, bl);
encode(account_pool, bl);
+ encode(group_pool, bl);
ENCODE_FINISH(bl);
}
if (struct_v >= 15) {
decode(topics_pool, bl);
decode(account_pool, bl);
+ decode(group_pool, bl);
} else {
topics_pool = name + ".rgw.meta:topics";
account_pool = name + ".rgw.meta:accounts";
+ group_pool = name + ".rgw.meta:groups";
}
DECODE_FINISH(bl);
}
i->path = "/";
i->create_date = ceph::real_time{std::chrono::hours(1)};
i->tags.emplace("key", "value");
+ i->group_ids.insert("group");
RGWAccessKey k1, k2;
k1.id = "id1";
k1.key = "key1";
encode_json("path", path, f);
encode_json("create_date", create_date, f);
encode_json("tags", tags, f);
+ encode_json("group_ids", group_ids, f);
}
void RGWUserInfo::decode_json(JSONObj *obj)
JSONDecoder::decode_json("path", path, obj);
JSONDecoder::decode_json("create_date", create_date, obj);
JSONDecoder::decode_json("tags", tags, obj);
+ JSONDecoder::decode_json("group_ids", group_ids, obj);
}
#include <unordered_map>
#include <fmt/format.h>
+#include <boost/container/flat_map.hpp>
+#include <boost/container/flat_set.hpp>
#include "common/ceph_crypto.h"
#include "common/random_string.h"
std::string path = "/";
ceph::real_time create_date;
std::multimap<std::string, std::string> tags;
+ boost::container::flat_set<std::string, std::less<>> group_ids;
RGWUserInfo()
: suspended(0),
encode(path, bl);
encode(create_date, bl);
encode(tags, bl);
+ encode(group_ids, bl);
ENCODE_FINISH(bl);
}
void decode(bufferlist::const_iterator& bl) {
decode(path, bl);
decode(create_date, bl);
decode(tags, bl);
+ decode(group_ids, bl);
} else {
path = "/";
}
std::string next_marker;
};
+/// A list of groups
+struct GroupList {
+ /// The list of results, sorted by name
+ std::vector<RGWGroupInfo> groups;
+ /// The next marker to resume listing, or empty
+ std::string next_marker;
+};
+
/** A list of key-value attributes */
using Attrs = std::map<std::string, ceph::buffer::list>;
uint32_t max_items,
UserList& listing) = 0;
+ /// @group Group
+ ///@{
+ /** Load an account's group by id. */
+ virtual int load_group_by_id(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view id,
+ RGWGroupInfo& info, Attrs& attrs,
+ RGWObjVersionTracker& objv) = 0;
+ /** Load an account's group by name. */
+ virtual int load_group_by_name(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view account_id,
+ std::string_view name,
+ RGWGroupInfo& info, Attrs& attrs,
+ RGWObjVersionTracker& objv) = 0;
+ /** Write or overwrite a group. */
+ virtual int store_group(const DoutPrefixProvider* dpp, optional_yield y,
+ const RGWGroupInfo& info, const Attrs& attrs,
+ RGWObjVersionTracker& objv, bool exclusive,
+ const RGWGroupInfo* old_info) = 0;
+ /** Remove a group. */
+ virtual int remove_group(const DoutPrefixProvider* dpp, optional_yield y,
+ const RGWGroupInfo& info,
+ RGWObjVersionTracker& objv) = 0;
+ /** Return a paginated listing of the group's users. */
+ virtual int list_group_users(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view tenant,
+ std::string_view id,
+ std::string_view marker,
+ uint32_t max_items,
+ UserList& listing) = 0;
+ /** Count the number of groups belonging to the given account. */
+ virtual int count_account_groups(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view account_id,
+ uint32_t& count) = 0;
+ /** Return a paginated listing of the account's groups. */
+ virtual int list_account_groups(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view account_id,
+ std::string_view path_prefix,
+ std::string_view marker,
+ uint32_t max_items,
+ GroupList& listing) = 0;
+ ///@}
+
/** Get a basic Object. This Object is not looked up, and is incomplete, since is
* does not have a bucket. This should only be used when an Object is needed before
* there is a Bucket, otherwise use the get_object() in the Bucket class. */
virtual int remove_user(const DoutPrefixProvider* dpp, optional_yield y) = 0;
/** Verify multi-factor authentication for this user */
virtual int verify_mfa(const std::string& mfa_str, bool* verified, const DoutPrefixProvider* dpp, optional_yield y) = 0;
+ /** Return a paginated listing of the user's groups. */
+ virtual int list_groups(const DoutPrefixProvider* dpp, optional_yield y,
+ std::string_view marker, uint32_t max_items,
+ GroupList& listing) = 0;
/* dang temporary; will be removed when User is complete */
virtual RGWUserInfo& get_info() = 0;
return 0;
}
+ int DBUser::list_groups(const DoutPrefixProvider* dpp, optional_yield y,
+ std::string_view marker, uint32_t max_items,
+ GroupList& listing)
+ {
+ return -ENOTSUP;
+ }
+
int DBBucket::remove(const DoutPrefixProvider *dpp, bool delete_children, optional_yield y)
{
int ret;
return -ENOTSUP;
}
+ int DBStore::load_group_by_id(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view id,
+ RGWGroupInfo& info, Attrs& attrs,
+ RGWObjVersionTracker& objv)
+ {
+ return -ENOTSUP;
+ }
+
+ int DBStore::load_group_by_name(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view account_id,
+ std::string_view name,
+ RGWGroupInfo& info, Attrs& attrs,
+ RGWObjVersionTracker& objv)
+ {
+ return -ENOTSUP;
+ }
+
+ int DBStore::store_group(const DoutPrefixProvider* dpp, optional_yield y,
+ const RGWGroupInfo& info, const Attrs& attrs,
+ RGWObjVersionTracker& objv, bool exclusive,
+ const RGWGroupInfo* old_info)
+ {
+ return -ENOTSUP;
+ }
+
+ int DBStore::remove_group(const DoutPrefixProvider* dpp, optional_yield y,
+ const RGWGroupInfo& info,
+ RGWObjVersionTracker& objv)
+ {
+ return -ENOTSUP;
+ }
+
+ int DBStore::list_group_users(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view tenant,
+ std::string_view id,
+ std::string_view marker,
+ uint32_t max_items,
+ UserList& listing)
+ {
+ return -ENOTSUP;
+ }
+
+ int DBStore::count_account_groups(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view account_id,
+ uint32_t& count)
+ {
+ return -ENOTSUP;
+ }
+
+ int DBStore::list_account_groups(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view account_id,
+ std::string_view path_prefix,
+ std::string_view marker,
+ uint32_t max_items,
+ GroupList& listing)
+ {
+ return -ENOTSUP;
+ }
+
std::string DBStore::get_cluster_id(const DoutPrefixProvider* dpp, optional_yield y)
{
return "PLACEHOLDER"; // for instance unique identifier
virtual int store_user(const DoutPrefixProvider* dpp, optional_yield y, bool exclusive, RGWUserInfo* old_info = nullptr) override;
virtual int remove_user(const DoutPrefixProvider* dpp, optional_yield y) override;
virtual int verify_mfa(const std::string& mfa_str, bool* verified, const DoutPrefixProvider* dpp, optional_yield y) override;
+ int list_groups(const DoutPrefixProvider* dpp, optional_yield y,
+ std::string_view marker, uint32_t max_items,
+ GroupList& listing) override;
friend class DBBucket;
};
uint32_t max_items,
UserList& listing) override;
+ int load_group_by_id(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view id,
+ RGWGroupInfo& info, Attrs& attrs,
+ RGWObjVersionTracker& objv) override;
+ int load_group_by_name(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view account_id,
+ std::string_view name,
+ RGWGroupInfo& info, Attrs& attrs,
+ RGWObjVersionTracker& objv) override;
+ int store_group(const DoutPrefixProvider* dpp, optional_yield y,
+ const RGWGroupInfo& info, const Attrs& attrs,
+ RGWObjVersionTracker& objv, bool exclusive,
+ const RGWGroupInfo* old_info) override;
+ int remove_group(const DoutPrefixProvider* dpp, optional_yield y,
+ const RGWGroupInfo& info,
+ RGWObjVersionTracker& objv) override;
+ int list_group_users(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view tenant,
+ std::string_view id,
+ std::string_view marker,
+ uint32_t max_items,
+ UserList& listing) override;
+ int count_account_groups(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view account_id,
+ uint32_t& count) override;
+ int list_account_groups(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view account_id,
+ std::string_view path_prefix,
+ std::string_view marker,
+ uint32_t max_items,
+ GroupList& listing) override;
+
virtual std::unique_ptr<Object> get_object(const rgw_obj_key& k) override;
virtual std::string get_cluster_id(const DoutPrefixProvider* dpp, optional_yield y);
std::unique_ptr<Bucket> get_bucket(const RGWBucketInfo& i) override;
marker, max_items, listing);
}
+int FilterDriver::load_group_by_id(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view id,
+ RGWGroupInfo& info, Attrs& attrs,
+ RGWObjVersionTracker& objv)
+{
+ return next->load_group_by_id(dpp, y, id, info, attrs, objv);
+}
+
+int FilterDriver::load_group_by_name(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view account_id,
+ std::string_view name,
+ RGWGroupInfo& info, Attrs& attrs,
+ RGWObjVersionTracker& objv)
+{
+ return next->load_group_by_name(dpp, y, account_id, name, info, attrs, objv);
+}
+
+int FilterDriver::store_group(const DoutPrefixProvider* dpp, optional_yield y,
+ const RGWGroupInfo& info, const Attrs& attrs,
+ RGWObjVersionTracker& objv, bool exclusive,
+ const RGWGroupInfo* old_info)
+{
+ return next->store_group(dpp, y, info, attrs, objv, exclusive, old_info);
+}
+
+int FilterDriver::remove_group(const DoutPrefixProvider* dpp, optional_yield y,
+ const RGWGroupInfo& info,
+ RGWObjVersionTracker& objv)
+{
+ return next->remove_group(dpp, y, info, objv);
+}
+
+int FilterDriver::list_group_users(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view tenant,
+ std::string_view id,
+ std::string_view marker,
+ uint32_t max_items,
+ UserList& listing)
+{
+ return next->list_group_users(dpp, y, tenant, id, marker, max_items, listing);
+}
+
+int FilterDriver::count_account_groups(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view account_id,
+ uint32_t& count)
+{
+ return next->count_account_groups(dpp, y, account_id, count);
+}
+
+int FilterDriver::list_account_groups(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view account_id,
+ std::string_view path_prefix,
+ std::string_view marker,
+ uint32_t max_items,
+ GroupList& listing)
+{
+ return next->list_account_groups(dpp, y, account_id, path_prefix,
+ marker, max_items, listing);
+}
+
std::unique_ptr<Object> FilterDriver::get_object(const rgw_obj_key& k)
{
std::unique_ptr<Object> o = next->get_object(k);
return next->verify_mfa(mfa_str, verified, dpp, y);
}
+int FilterUser::list_groups(const DoutPrefixProvider* dpp, optional_yield y,
+ std::string_view marker, uint32_t max_items,
+ GroupList& listing)
+{
+ return next->list_groups(dpp, y, marker, max_items, listing);
+}
+
std::unique_ptr<Object> FilterBucket::get_object(const rgw_obj_key& k)
{
std::unique_ptr<Object> o = next->get_object(k);
uint32_t max_items,
UserList& listing) override;
+ int load_group_by_id(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view id,
+ RGWGroupInfo& info, Attrs& attrs,
+ RGWObjVersionTracker& objv) override;
+ int load_group_by_name(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view account_id,
+ std::string_view name,
+ RGWGroupInfo& info, Attrs& attrs,
+ RGWObjVersionTracker& objv) override;
+ int store_group(const DoutPrefixProvider* dpp, optional_yield y,
+ const RGWGroupInfo& info, const Attrs& attrs,
+ RGWObjVersionTracker& objv, bool exclusive,
+ const RGWGroupInfo* old_info) override;
+ int remove_group(const DoutPrefixProvider* dpp, optional_yield y,
+ const RGWGroupInfo& info,
+ RGWObjVersionTracker& objv) override;
+ int list_group_users(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view tenant,
+ std::string_view id,
+ std::string_view marker,
+ uint32_t max_items,
+ UserList& listing) override;
+ int count_account_groups(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view account_id,
+ uint32_t& count) override;
+ int list_account_groups(const DoutPrefixProvider* dpp,
+ optional_yield y,
+ std::string_view account_id,
+ std::string_view path_prefix,
+ std::string_view marker,
+ uint32_t max_items,
+ GroupList& listing) override;
+
virtual std::unique_ptr<Object> get_object(const rgw_obj_key& k) override;
std::unique_ptr<Bucket> get_bucket(const RGWBucketInfo& i) override;
int load_bucket(const DoutPrefixProvider* dpp, const rgw_bucket& b,
virtual int remove_user(const DoutPrefixProvider* dpp, optional_yield y) override;
virtual int verify_mfa(const std::string& mfa_str, bool* verified,
const DoutPrefixProvider* dpp, optional_yield y) override;
+ int list_groups(const DoutPrefixProvider* dpp, optional_yield y,
+ std::string_view marker, uint32_t max_items,
+ GroupList& listing) override;
RGWUserInfo& get_info() override { return next->get_info(); }
virtual void print(std::ostream& out) const override { return next->print(out); }
struct RGWRoleInfo;
class RGWRole;
struct RoleList;
+ struct GroupList;
class DataProcessor;
class ObjectProcessor;
class ReadStatsCB;
JSONDecoder::decode_json("notif_pool", notif_pool, obj);
JSONDecoder::decode_json("topics_pool", topics_pool, obj);
JSONDecoder::decode_json("account_pool", account_pool, obj);
+ JSONDecoder::decode_json("group_pool", group_pool, obj);
JSONDecoder::decode_json("system_key", system_key, obj);
JSONDecoder::decode_json("placement_pools", placement_pools, obj);
JSONDecoder::decode_json("tier_config", tier_config, obj);
encode_json("notif_pool", notif_pool, f);
encode_json("topics_pool", topics_pool, f);
encode_json("account_pool", account_pool, f);
+ encode_json("group_pool", group_pool, f);
encode_json_plain("system_key", system_key, f);
encode_json("placement_pools", placement_pools, f);
encode_json("tier_config", tier_config, f);
pools.insert(info.notif_pool);
pools.insert(info.topics_pool);
pools.insert(info.account_pool);
+ pools.insert(info.group_pool);
for (const auto& [pname, placement] : info.placement_pools) {
pools.insert(placement.index_pool);
notif_pool = fix_zone_pool_dup(pools, name ,".rgw.log:notif", notif_pool);
topics_pool = fix_zone_pool_dup(pools, name, ".rgw.meta:topics", topics_pool);
account_pool = fix_zone_pool_dup(pools, name, ".rgw.meta:accounts", account_pool);
+ group_pool = fix_zone_pool_dup(pools, name, ".rgw.meta:groups", group_pool);
for(auto& iter : placement_pools) {
iter.second.index_pool = fix_zone_pool_dup(pools, name, "." + default_bucket_index_pool_suffix,
info.topics_pool =
fix_zone_pool_dup(pools, info.name, ".rgw.meta:topics", info.topics_pool);
info.account_pool = fix_zone_pool_dup(pools, info.name, ".rgw.meta:accounts", info.account_pool);
+ info.group_pool = fix_zone_pool_dup(pools, info.name, ".rgw.meta:groups", info.group_pool);
for (auto& [pname, placement] : info.placement_pools) {
placement.index_pool = fix_zone_pool_dup(pools, info.name, "." + default_bucket_index_pool_suffix, placement.index_pool);
#include "driver/rados/account.h"
#include "driver/rados/buckets.h"
+#include "driver/rados/group.h"
#include "driver/rados/users.h"
#define dout_subsys ceph_subsys_rgw
<< " to account " << info.account_id << dendl;
}
+ for (const auto& group_id : info.group_ids) {
+ if (old_info && old_info->group_ids.count(group_id)) {
+ continue;
+ }
+ // link the user to its group
+ const RGWZoneParams& zone = svc.zone->get_zone_params();
+ const auto& users = rgwrados::group::get_users_obj(zone, group_id);
+ ret = rgwrados::users::add(dpp, y, rados, users, info, false,
+ std::numeric_limits<uint32_t>::max());
+ if (ret < 0) {
+ ldpp_dout(dpp, 20) << "WARNING: failed to link user "
+ << info.user_id << " to group " << group_id
+ << ": " << cpp_strerror(ret) << dendl;
+ return ret;
+ }
+ ldpp_dout(dpp, 20) << "linked user " << info.user_id
+ << " to group " << group_id << dendl;
+ }
+
return 0;
}
}
}
+ for (const auto& group_id : old_info.group_ids) {
+ if (info.group_ids.count(group_id)) {
+ continue;
+ }
+ // remove from the old group
+ const RGWZoneParams& zone = svc.zone->get_zone_params();
+ const auto& users = rgwrados::group::get_users_obj(zone, group_id);
+ ret = rgwrados::users::remove(dpp, y, rados, users, old_info.display_name);
+ if (ret < 0 && ret != -ENOENT) {
+ set_err_msg("ERROR: could not unlink from group " + group_id);
+ return ret;
+ }
+ }
+
return 0;
}
}
}
+ for (const auto& group_id : info.group_ids) {
+ const RGWZoneParams& zone = svc.zone->get_zone_params();
+ const auto& users = rgwrados::group::get_users_obj(zone, group_id);
+ ret = rgwrados::users::remove(dpp, y, *rados, users, info.display_name);
+ if (ret < 0 && ret != -ENOENT) {
+ ldpp_dout(dpp, 0) << "ERROR: could not unlink from group "
+ << group_id << ": " << cpp_strerror(ret) << dendl;
+ return ret;
+ }
+ }
+
ret = remove_uid_index(ctx, info, objv_tracker, y, dpp);
if (ret < 0 && ret != -ENOENT) {
return ret;
virtual int verify_mfa(const std::string& mfa_str, bool* verified, const DoutPrefixProvider* dpp, optional_yield y) override {
return 0;
}
+ int list_groups(const DoutPrefixProvider* dpp, optional_yield y,
+ std::string_view marker, uint32_t max_items,
+ rgw::sal::GroupList& listing) override {
+ return 0;
+ }
virtual ~TestUser() = default;
};
#include "rgw_oidc_provider.h"
TYPE(RGWOIDCProviderInfo)
+#include "driver/rados/groups.h"
+TYPE(rgwrados::groups::resource_metadata)
+
#include "driver/rados/roles.h"
TYPE(rgwrados::roles::resource_metadata)