]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
RGW | standalone: add support for accounts in dbstore
authorAli Masarwa <amasarwa@redhat.com>
Sun, 12 Apr 2026 13:07:38 +0000 (16:07 +0300)
committerDaniel Gryniewicz <dang@fprintf.net>
Fri, 29 May 2026 16:05:12 +0000 (12:05 -0400)
Signed-off-by: Ali Masarwa <amasarwa@redhat.com>
src/rgw/driver/dbstore/common/dbstore.cc
src/rgw/driver/dbstore/common/dbstore.h
src/rgw/driver/dbstore/sqlite/sqliteDB.cc
src/rgw/driver/dbstore/sqlite/sqliteDB.h
src/rgw/driver/posix/posixDB.cc
src/rgw/driver/posix/posixDB.h
src/rgw/driver/posix/rgw_sal_posix.cc
src/rgw/driver/posix/rgw_sal_posix.h

index 6db081ca3043d75929ba85a1205b0793bbeb1d70..bf8edcdbb2eb891dcc2d108b22a954259aeafb98 100644 (file)
@@ -234,6 +234,7 @@ int DB::InitializeParams(const DoutPrefixProvider *dpp, DBOpParams *params)
   params->cct = cct;
 
   //reset params here
+  params->account_table = account_table;
   params->user_table = user_table;
   params->bucket_table = bucket_table;
   params->quota_table = quota_table;
@@ -430,6 +431,157 @@ out:
   return ret;
 }
 
+int DB::get_account(const DoutPrefixProvider *dpp,
+    const std::string& query_str, const std::string& query_str_val,
+    RGWAccountInfo& ainfo, map<string, bufferlist> *pattrs,
+    RGWObjVersionTracker *pobjv_tracker) {
+  int ret = 0;
+
+  if (query_str.empty() || query_str_val.empty()) {
+    ldpp_dout(dpp, 0)<<"In GetAccount - Invalid query(" << query_str <<"), query_str_val(" << query_str_val <<")" << dendl;
+    return -1;
+  }
+
+  DBOpParams params = {};
+  InitializeParams(dpp, &params);
+
+  params.op.query_str = query_str;
+
+  // validate query_str with AccountTable entries names
+  if (query_str == "name") {
+    params.op.account.info.name = query_str_val;
+  } else if (query_str == "email") {
+    params.op.account.info.email = query_str_val;
+  } else if (query_str == "account_id") {
+    params.op.account.info.id = query_str_val;
+  } else {
+    ldpp_dout(dpp, 0)<<"In GetAccount Invalid query string :" <<query_str.c_str()<<") " << dendl;
+    return -1;
+  }
+
+  ret = ProcessOp(dpp, "GetAccount", &params);
+
+  if (ret) {
+    return ret;
+  }
+
+  /* Verify if its a valid account */
+  if (params.op.account.info.id.empty()) {
+    ldpp_dout(dpp, 0)<<"In GetAccount - No account with query(" <<query_str.c_str()<<"), account_id(" << ainfo.id <<") found" << dendl;
+    return -ENOENT;
+  }
+
+  ainfo = params.op.account.info;
+
+  if (pattrs) {
+    *pattrs = params.op.account.account_attrs;
+  }
+
+  if (pobjv_tracker) {
+    pobjv_tracker->read_version = params.op.account.account_version;
+  }
+
+  return ret;
+}
+
+int DB::store_account(const DoutPrefixProvider *dpp,
+    const RGWAccountInfo& ainfo, bool exclusive, const map<string, bufferlist> *pattrs,
+    RGWObjVersionTracker *pobjv)
+{
+  DBOpParams params = {};
+  InitializeParams(dpp, &params);
+  int ret = 0;
+
+  /* Check if the account already exists and return the old info, caller will have a use for it */
+  RGWAccountInfo orig_info;
+  RGWObjVersionTracker objv_tracker = {};
+  obj_version& obj_ver = objv_tracker.read_version;
+
+  orig_info.id = ainfo.id;
+  ret = get_account(dpp, string("account_id"), ainfo.id, orig_info, nullptr, &objv_tracker);
+
+  if (!ret && obj_ver.ver) {
+    /* already exists. */
+    if (pobjv && (pobjv->read_version.ver != obj_ver.ver)) {
+      /* Object version mismatch.. return ECANCELED */
+      ret = -ECANCELED;
+      ldpp_dout(dpp, 0)<<"Account Read version mismatch err:(" <<ret<<") " << dendl;
+      return ret;
+    }
+
+    if (exclusive) {
+      // return
+      return ret;
+    }
+    obj_ver.ver++;
+  } else {
+    obj_ver.ver = 1;
+    obj_ver.tag = "AccountTAG";
+  }
+
+  params.op.account.account_version = obj_ver;
+  params.op.account.info = ainfo;
+
+  if (pattrs) {
+    params.op.account.account_attrs = *pattrs;
+  }
+
+  ret = ProcessOp(dpp, "InsertAccount", &params);
+
+  if (ret) {
+    ldpp_dout(dpp, 0)<<"store_account failed with err:(" <<ret<<") " << dendl;
+    return ret;
+  }
+  ldpp_dout(dpp, 20)<<"Account creation successful - account_id:(" <<ainfo.id<<") " << dendl;
+
+  if (pobjv) {
+    pobjv->read_version = obj_ver;
+    pobjv->write_version = obj_ver;
+  }
+
+  return ret;
+}
+
+int DB::remove_account(const DoutPrefixProvider *dpp,
+    const RGWAccountInfo &ainfo, RGWObjVersionTracker *pobjv)
+{
+  DBOpParams params = {};
+  InitializeParams(dpp, &params);
+  int ret = 0;
+
+  RGWAccountInfo orig_info;
+  RGWObjVersionTracker objv_tracker = {};
+
+  orig_info.id = ainfo.id;
+  ret = get_account(dpp, string("account_id"), ainfo.id, orig_info, nullptr, &objv_tracker);
+
+  if (ret) {
+    return ret;
+  }
+
+  if (!ret && objv_tracker.read_version.ver) {
+    /* already exists. */
+
+    if (pobjv && (pobjv->read_version.ver != objv_tracker.read_version.ver)) {
+      /* Object version mismatch.. return ECANCELED */
+      ret = -ECANCELED;
+      ldpp_dout(dpp, 0)<<"Account Read version mismatch err:(" <<ret<<") " << dendl;
+      return ret;
+    }
+  }
+
+  params.op.account.info.id = ainfo.id;
+
+  ret = ProcessOp(dpp, "RemoveAccount", &params);
+
+  if (ret) {
+    ldpp_dout(dpp, 0)<<"remove_account failed with err:(" <<ret<<") " << dendl;
+    return ret;
+  }
+
+  return ret;
+}
+
 int DB::get_bucket_info(const DoutPrefixProvider *dpp, const std::string& query_str,
     const std::string& query_str_val,
     RGWBucketInfo& info,
index 7c854dcbaefe047363e637b1f8dcd7dc3bfd23d8..d038600b8125d4718833916870ccdc8b283da5e8 100644 (file)
@@ -26,6 +26,12 @@ namespace rgw { namespace store {
 
 class DB;
 
+struct DBOpAccountInfo {
+  RGWAccountInfo info = {};
+  obj_version account_version;
+  rgw::sal::Attrs account_attrs;
+};
+
 struct DBOpUserInfo {
   RGWUserInfo uinfo = {};
   obj_version user_version;
@@ -122,6 +128,7 @@ struct DBOpInfo {
    * be able to query easily.
    *
    * XXX: Swift keys and subuser not supported for now */
+  DBOpAccountInfo account;
   DBOpUserInfo user;
   std::string query_str;
   DBOpBucketInfo bucket;
@@ -136,6 +143,7 @@ struct DBOpParams {
   CephContext *cct;
 
   /* Tables */
+  std::string account_table;
   std::string user_table;
   std::string bucket_table;
   std::string object_table;
@@ -162,6 +170,20 @@ struct DBOpParams {
  * These identifiers are used in prepare and bind statements
  * to get the right index of each param.
  */
+struct DBOpAccountPrepareInfo {
+  static constexpr const char* account_id = ":account_id";
+  static constexpr const char* tenant = ":tenant";
+  static constexpr const char* account_name = ":account_name";
+  static constexpr const char* email = ":email";
+  static constexpr const char* quota = ":quota";
+  static constexpr const char* bucket_quota = ":bucket_quota";
+  static constexpr const char* max_users = ":max_users";
+  static constexpr const char* max_roles = ":max_roles";
+  static constexpr const char* max_groups = ":max_groups";
+  static constexpr const char* max_buckets = ":max_buckets";
+  static constexpr const char* max_access_keys = ":max_access_keys";
+};
+
 struct DBOpUserPrepareInfo {
   static constexpr const char* user_id = ":user_id";
   static constexpr const char* tenant = ":tenant";
@@ -313,6 +335,7 @@ struct DBOpLCHeadPrepareInfo {
 };
 
 struct DBOpPrepareInfo {
+  DBOpAccountPrepareInfo account;
   DBOpUserPrepareInfo user;
   std::string_view query_str; // view into DBOpInfo::query_str
   DBOpBucketPrepareInfo bucket;
@@ -325,6 +348,7 @@ struct DBOpPrepareInfo {
 
 struct DBOpPrepareParams {
   /* Tables */
+  std::string account_table;
   std::string user_table;
   std::string bucket_table;
   std::string object_table;
@@ -342,6 +366,9 @@ struct DBOpPrepareParams {
 };
 
 struct DBOps {
+  std::shared_ptr<class InsertAccountOp> InsertAccount;
+  std::shared_ptr<class RemoveAccountOp> RemoveAccount;
+  std::shared_ptr<class GetAccountOp> GetAccount;
   std::shared_ptr<class InsertUserOp> InsertUser;
   std::shared_ptr<class RemoveUserOp> RemoveUser;
   std::shared_ptr<class GetUserOp> GetUser;
@@ -382,6 +409,30 @@ class ObjectOp {
 
 class DBOp {
   private:
+    static constexpr std::string_view CreateAccountTableQ =
+      /* Corresponds to RGWAccountInfo
+       *
+       * AccountID is made Primary key.
+       * If multiple tenants are stored in single .db handle, should
+       * make both (AccountID, Tenant) as Primary Key.
+       *
+       * XXX:
+       * - Quota stored as blob .. should be linked to quota table.
+       */
+      "CREATE TABLE IF NOT EXISTS '{}' (       \
+      AccountID TEXT NOT NULL UNIQUE,          \
+      Tenant TEXT ,            \
+      AccountName TEXT , \
+      Email TEXT ,     \
+      Quota BLOB ,     \
+      BucketQuota BLOB ,       \
+      MaxUsers INTEGER ,       \
+      MaxRoles INTEGER ,       \
+      MaxGroups INTEGER ,      \
+      MaxBuckets INTEGER ,     \
+      MaxAccessKeys INTEGER ,  \
+      PRIMARY KEY (AccountID) \n);";
+
     static constexpr std::string_view CreateUserTableQ =
       /* Corresponds to rgw::sal::User
        *
@@ -653,6 +704,9 @@ class DBOp {
 
     static std::string CreateTableSchema(std::string_view type,
                                          const DBOpParams *params) {
+      if (!type.compare("Account"))
+        return fmt::format(CreateAccountTableQ,
+            params->account_table);
       if (!type.compare("User"))
         return fmt::format(CreateUserTableQ,
             params->user_table);
@@ -705,6 +759,76 @@ class DBOp {
     virtual int Execute(const DoutPrefixProvider *dpp, DBOpParams *params) { return 0; }
 };
 
+class InsertAccountOp : virtual public DBOp {
+  private:
+    static constexpr std::string_view Query = "INSERT OR REPLACE INTO '{}'     \
+                          (AccountID, Tenant, AccountName, Email, \
+                           Quota, BucketQuota, MaxUsers, MaxRoles, MaxGroups, \
+                           MaxBuckets, MaxAccessKeys) \
+                          VALUES ({}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {});";
+
+  public:
+    virtual ~InsertAccountOp() {}
+
+    static std::string Schema(DBOpPrepareParams &params) {
+      return fmt::format(Query, params.account_table,
+          params.op.account.account_id, params.op.account.tenant,
+          params.op.account.account_name, params.op.account.email,
+          params.op.account.quota, params.op.account.bucket_quota,
+          params.op.account.max_users, params.op.account.max_roles,
+          params.op.account.max_groups, params.op.account.max_buckets,
+          params.op.account.max_access_keys);
+    }
+};
+
+class RemoveAccountOp: virtual public DBOp {
+  private:
+    static constexpr std::string_view Query =
+      "DELETE from '{}' where AccountID = {}";
+
+  public:
+    virtual ~RemoveAccountOp() {}
+
+    static std::string Schema(DBOpPrepareParams &params) {
+      return fmt::format(Query, params.account_table,
+          params.op.account.account_id);
+    }
+};
+
+class GetAccountOp: virtual public DBOp {
+  private:
+    static constexpr std::string_view Query = "SELECT \
+                          AccountID, Tenant, AccountName, Email, \
+                          Quota, BucketQuota, MaxUsers, MaxRoles, MaxGroups, \
+                          MaxBuckets, MaxAccessKeys from '{}' where AccountID = {}";
+
+    static constexpr std::string_view QueryByName = "SELECT \
+                          AccountID, Tenant, AccountName, Email, \
+                          Quota, BucketQuota, MaxUsers, MaxRoles, MaxGroups, \
+                          MaxBuckets, MaxAccessKeys from '{}' where AccountName = {}";
+
+    static constexpr std::string_view QueryByEmail = "SELECT \
+                          AccountID, Tenant, AccountName, Email, \
+                          Quota, BucketQuota, MaxUsers, MaxRoles, MaxGroups, \
+                          MaxBuckets, MaxAccessKeys from '{}' where Email = {}";
+
+  public:
+    virtual ~GetAccountOp() {}
+
+    static std::string Schema(DBOpPrepareParams &params) {
+      if (params.op.query_str == "name") {
+        return fmt::format(QueryByName, params.account_table,
+            params.op.account.account_name);
+      } else if (params.op.query_str == "email") {
+        return fmt::format(QueryByEmail, params.account_table,
+            params.op.account.email);
+      } else {
+        return fmt::format(Query, params.account_table,
+            params.op.account.account_id);
+      }
+    }
+};
+
 class InsertUserOp : virtual public DBOp {
   private:
     /* For existing entires, -
@@ -1480,6 +1604,7 @@ class DB {
   private:
     const std::string db_name;
     rgw::sal::Driver* driver;
+    const std::string account_table;
     const std::string user_table;
     const std::string bucket_table;
     const std::string quota_table;
@@ -1501,6 +1626,7 @@ class DB {
 
   public:
     DB(std::string db_name, CephContext *_cct) : db_name(db_name),
+    account_table(db_name+"_account_table"),
     user_table(db_name+"_user_table"),
     bucket_table(db_name+"_bucket_table"),
     quota_table(db_name+"_quota_table"),
@@ -1512,6 +1638,7 @@ class DB {
     /* DB() {}*/
 
     DB(CephContext *_cct) : db_name("default_db"),
+    account_table(db_name+"_account_table"),
     user_table(db_name+"_user_table"),
     bucket_table(db_name+"_bucket_table"),
     quota_table(db_name+"_quota_table"),
@@ -1524,6 +1651,7 @@ class DB {
 
     const std::string getDBname() { return db_name; }
     const std::string getDBfile() { return db_name + ".db"; }
+    const std::string getAccountTable() { return account_table; }
     const std::string getUserTable() { return user_table; }
     const std::string getBucketTable() { return bucket_table; }
     const std::string getQuotaTable() { return quota_table; }
@@ -1589,6 +1717,15 @@ class DB {
         RGWObjVersionTracker *pobjv_tracker, RGWUserInfo* pold_info);
     int remove_user(const DoutPrefixProvider *dpp,
         RGWUserInfo& uinfo, RGWObjVersionTracker *pobjv_tracker);
+    int get_account(const DoutPrefixProvider *dpp,
+        const std::string& query_str, const std::string& query_str_val,
+        RGWAccountInfo& ainfo, std::map<std::string, bufferlist> *pattrs,
+        RGWObjVersionTracker *pobjv_tracker);
+    int store_account(const DoutPrefixProvider *dpp,
+        const RGWAccountInfo& ainfo, bool exclusive, const std::map<std::string, bufferlist> *pattrs,
+        RGWObjVersionTracker *pobjv_tracker);
+    int remove_account(const DoutPrefixProvider *dpp,
+        const RGWAccountInfo &ainfo, RGWObjVersionTracker *pobjv_tracker);
     int get_bucket_info(const DoutPrefixProvider *dpp, const std::string& query_str,
         const std::string& query_str_val,
         RGWBucketInfo& info, rgw::sal::Attrs* pattrs, ceph::real_time* pmtime,
index dc341ac7e982c6719a6208bd302d9bca79137878..ac573c4fd06d5a2563ec1fec3f58cae2dd3e4791 100644 (file)
@@ -157,8 +157,8 @@ int SQLiteDB::InitPrepareParams(const DoutPrefixProvider *dpp,
   if (!params)
     return -1;
 
-  if (params->user_table.empty()) {
-    params->user_table = getUserTable();
+  if (params->account_table.empty()) {
+    params->account_table = getAccountTable();
   }
   if (params->user_table.empty()) {
     params->user_table = getUserTable();
@@ -176,6 +176,7 @@ int SQLiteDB::InitPrepareParams(const DoutPrefixProvider *dpp,
     params->lc_head_table = getLCHeadTable();
   }
 
+  p_params.account_table = params->account_table;
   p_params.user_table = params->user_table;
   p_params.bucket_table = params->bucket_table;
   p_params.quota_table = params->quota_table;
@@ -217,6 +218,20 @@ static int list_callback(void *None, int argc, char **argv, char **aname)
   return 0;
 }
 
+enum GetAccount {
+  AccountID = 0,
+  AccountTenant,
+  AccountName,
+  Email,
+  AccountQuota,
+  AccountBucketQuota,
+  MaxUsers,
+  MaxRoles,
+  MaxGroups,
+  AccountMaxBuckets,
+  MaxAccessKeys,
+};
+
 enum GetUser {
   UserID = 0,
   Tenant,
@@ -359,6 +374,27 @@ enum GetLCHead {
   LCHeadStartDate
 };
 
+static int list_account(const DoutPrefixProvider *dpp, DBOpInfo &op, sqlite3_stmt *stmt) {
+  if (!stmt)
+    return -1;
+
+  op.account.info.id = (const char*)sqlite3_column_text(stmt, AccountID);
+  op.account.info.tenant = (const char*)sqlite3_column_text(stmt, AccountTenant);
+  op.account.info.name = (const char*)sqlite3_column_text(stmt, AccountName);
+  op.account.info.email = (const char*)sqlite3_column_text(stmt, Email);
+
+  SQL_DECODE_BLOB_PARAM(dpp, stmt, AccountQuota, op.account.info.quota, sdb);
+  SQL_DECODE_BLOB_PARAM(dpp, stmt, AccountBucketQuota, op.account.info.bucket_quota, sdb);
+
+  op.account.info.max_users = sqlite3_column_int(stmt, MaxUsers);
+  op.account.info.max_roles = sqlite3_column_int(stmt, MaxRoles);
+  op.account.info.max_groups = sqlite3_column_int(stmt, MaxGroups);
+  op.account.info.max_buckets = sqlite3_column_int(stmt, AccountMaxBuckets);
+  op.account.info.max_access_keys = sqlite3_column_int(stmt, MaxAccessKeys);
+
+  return 0;
+}
+
 static int list_user(const DoutPrefixProvider *dpp, DBOpInfo &op, sqlite3_stmt *stmt) {
   if (!stmt)
     return -1;
@@ -588,6 +624,9 @@ static int list_lc_head(const DoutPrefixProvider *dpp, DBOpInfo &op, sqlite3_stm
 int SQLiteDB::InitializeDBOps(const DoutPrefixProvider *dpp)
 {
   (void)createTables(dpp);
+  dbops.InsertAccount = make_shared<SQLInsertAccount>(&this->db, this->getDBname(), cct);
+  dbops.RemoveAccount = make_shared<SQLRemoveAccount>(&this->db, this->getDBname(), cct);
+  dbops.GetAccount = make_shared<SQLGetAccount>(&this->db, this->getDBname(), cct);
   dbops.InsertUser = make_shared<SQLInsertUser>(&this->db, this->getDBname(), cct);
   dbops.RemoveUser = make_shared<SQLRemoveUser>(&this->db, this->getDBname(), cct);
   dbops.GetUser = make_shared<SQLGetUser>(&this->db, this->getDBname(), cct);
@@ -716,12 +755,16 @@ out:
 int SQLiteDB::createTables(const DoutPrefixProvider *dpp)
 {
   int ret = -1;
-  int cu = 0, cb = 0, cq = 0;
+  int ca = 0, cu = 0, cb = 0, cq = 0;
   DBOpParams params = {};
 
+  params.account_table = getAccountTable();
   params.user_table = getUserTable();
   params.bucket_table = getBucketTable();
 
+  if ((ca = createAccountTable(dpp, &params)))
+    goto out;
+
   if ((cu = createUserTable(dpp, &params)))
     goto out;
 
@@ -734,6 +777,8 @@ int SQLiteDB::createTables(const DoutPrefixProvider *dpp)
   ret = 0;
 out:
   if (ret) {
+    if (ca)
+      DeleteAccountTable(dpp, &params);
     if (cu)
       DeleteUserTable(dpp, &params);
     if (cb)
@@ -744,6 +789,22 @@ out:
   return ret;
 }
 
+int SQLiteDB::createAccountTable(const DoutPrefixProvider *dpp, DBOpParams *params)
+{
+  int ret = -1;
+  string schema;
+
+  schema = CreateTableSchema("Account", params);
+
+  ret = exec(dpp, schema.c_str(), NULL);
+  if (ret)
+    ldpp_dout(dpp, 0)<<"CreateAccountTable failed" << dendl;
+
+  ldpp_dout(dpp, 20)<<"CreateAccountTable succeeded" << dendl;
+
+  return ret;
+}
+
 int SQLiteDB::createUserTable(const DoutPrefixProvider *dpp, DBOpParams *params)
 {
   int ret = -1;
@@ -885,6 +946,22 @@ int SQLiteDB::createLCTables(const DoutPrefixProvider *dpp)
   return ret;
 }
 
+int SQLiteDB::DeleteAccountTable(const DoutPrefixProvider *dpp, DBOpParams *params)
+{
+  int ret = -1;
+  string schema;
+
+  schema = DeleteTableSchema(params->account_table);
+
+  ret = exec(dpp, schema.c_str(), NULL);
+  if (ret)
+    ldpp_dout(dpp, 0)<<"DeleteAccountTable failed " << dendl;
+
+  ldpp_dout(dpp, 20)<<"DeleteAccountTable succeeded " << dendl;
+
+  return ret;
+}
+
 int SQLiteDB::DeleteUserTable(const DoutPrefixProvider *dpp, DBOpParams *params)
 {
   int ret = -1;
@@ -1069,6 +1146,174 @@ int SQLObjectOp::InitializeObjectOps(string db_name, const DoutPrefixProvider *d
   return 0;
 }
 
+int SQLInsertAccount::Prepare(const DoutPrefixProvider *dpp, struct DBOpParams *params)
+{
+  int ret = -1;
+  struct DBOpPrepareParams p_params = PrepareParams;
+
+  if (!*sdb) {
+    ldpp_dout(dpp, 0)<<"In SQLInsertAccount - no db" << dendl;
+    goto out;
+  }
+
+  InitPrepareParams(dpp, p_params, params);
+
+  SQL_PREPARE(dpp, p_params, sdb, stmt, ret, "PrepareInsertAccount");
+out:
+  return ret;
+}
+
+int SQLInsertAccount::Bind(const DoutPrefixProvider *dpp, struct DBOpParams *params)
+{
+  int index = -1;
+  int rc = 0;
+  struct DBOpPrepareParams p_params = PrepareParams;
+
+  SQL_BIND_INDEX(dpp, stmt, index, p_params.op.account.account_id, sdb);
+  SQL_BIND_TEXT(dpp, stmt, index, params->op.account.info.id.c_str(), sdb);
+
+  SQL_BIND_INDEX(dpp, stmt, index, p_params.op.account.tenant, sdb);
+  SQL_BIND_TEXT(dpp, stmt, index, params->op.account.info.tenant.c_str(), sdb);
+
+  SQL_BIND_INDEX(dpp, stmt, index, p_params.op.account.account_name, sdb);
+  SQL_BIND_TEXT(dpp, stmt, index, params->op.account.info.name.c_str(), sdb);
+
+  SQL_BIND_INDEX(dpp, stmt, index, p_params.op.account.email, sdb);
+  SQL_BIND_TEXT(dpp, stmt, index, params->op.account.info.email.c_str(), sdb);
+
+  SQL_BIND_INDEX(dpp, stmt, index, p_params.op.account.quota, sdb);
+  SQL_ENCODE_BLOB_PARAM(dpp, stmt, index, params->op.account.info.quota, sdb);
+
+  SQL_BIND_INDEX(dpp, stmt, index, p_params.op.account.bucket_quota, sdb);
+  SQL_ENCODE_BLOB_PARAM(dpp, stmt, index, params->op.account.info.bucket_quota, sdb);
+
+  SQL_BIND_INDEX(dpp, stmt, index, p_params.op.account.max_users, sdb);
+  SQL_BIND_INT(dpp, stmt, index, params->op.account.info.max_users, sdb);
+
+  SQL_BIND_INDEX(dpp, stmt, index, p_params.op.account.max_roles, sdb);
+  SQL_BIND_INT(dpp, stmt, index, params->op.account.info.max_roles, sdb);
+
+  SQL_BIND_INDEX(dpp, stmt, index, p_params.op.account.max_groups, sdb);
+  SQL_BIND_INT(dpp, stmt, index, params->op.account.info.max_groups, sdb);
+
+  SQL_BIND_INDEX(dpp, stmt, index, p_params.op.account.max_buckets, sdb);
+  SQL_BIND_INT(dpp, stmt, index, params->op.account.info.max_buckets, sdb);
+
+  SQL_BIND_INDEX(dpp, stmt, index, p_params.op.account.max_access_keys, sdb);
+  SQL_BIND_INT(dpp, stmt, index, params->op.account.info.max_access_keys, sdb);
+
+out:
+  return rc;
+}
+
+int SQLInsertAccount::Execute(const DoutPrefixProvider *dpp, struct DBOpParams *params)
+{
+  int ret = -1;
+
+  SQL_EXECUTE(dpp, params, stmt, NULL);
+out:
+  return ret;
+}
+
+int SQLRemoveAccount::Prepare(const DoutPrefixProvider *dpp, struct DBOpParams *params)
+{
+  int ret = -1;
+  struct DBOpPrepareParams p_params = PrepareParams;
+
+  if (!*sdb) {
+    ldpp_dout(dpp, 0)<<"In SQLRemoveAccount - no db" << dendl;
+    goto out;
+  }
+
+  InitPrepareParams(dpp, p_params, params);
+
+  SQL_PREPARE(dpp, p_params, sdb, stmt, ret, "PrepareRemoveAccount");
+out:
+  return ret;
+}
+
+int SQLRemoveAccount::Bind(const DoutPrefixProvider *dpp, struct DBOpParams *params)
+{
+  int index = -1;
+  int rc = 0;
+  struct DBOpPrepareParams p_params = PrepareParams;
+
+  SQL_BIND_INDEX(dpp, stmt, index, p_params.op.account.account_id, sdb);
+  SQL_BIND_TEXT(dpp, stmt, index, params->op.account.info.id.c_str(), sdb);
+
+out:
+  return rc;
+}
+
+int SQLRemoveAccount::Execute(const DoutPrefixProvider *dpp, struct DBOpParams *params)
+{
+  int ret = -1;
+
+  SQL_EXECUTE(dpp, params, stmt, NULL);
+out:
+  return ret;
+}
+
+int SQLGetAccount::Prepare(const DoutPrefixProvider *dpp, struct DBOpParams *params)
+{
+  int ret = -1;
+  struct DBOpPrepareParams p_params = PrepareParams;
+
+  if (!*sdb) {
+    ldpp_dout(dpp, 0)<<"In SQLGetAccount - no db" << dendl;
+    goto out;
+  }
+
+  InitPrepareParams(dpp, p_params, params);
+
+  if (params->op.query_str == "name") { 
+    SQL_PREPARE(dpp, p_params, sdb, name_stmt, ret, "PrepareGetAccount");
+  } else if (params->op.query_str == "email") { 
+    SQL_PREPARE(dpp, p_params, sdb, email_stmt, ret, "PrepareGetAccount");
+  } else { // by default by account_id
+    SQL_PREPARE(dpp, p_params, sdb, stmt, ret, "PrepareGetAccount");
+  }
+out:
+  return ret;
+}
+
+int SQLGetAccount::Bind(const DoutPrefixProvider *dpp, struct DBOpParams *params)
+{
+  int index = -1;
+  int rc = 0;
+  struct DBOpPrepareParams p_params = PrepareParams;
+
+  if (params->op.query_str == "name") { 
+    SQL_BIND_INDEX(dpp, name_stmt, index, p_params.op.account.account_name, sdb);
+    SQL_BIND_TEXT(dpp, name_stmt, index, params->op.account.info.name.c_str(), sdb);
+  } else if (params->op.query_str == "email") { 
+    SQL_BIND_INDEX(dpp, email_stmt, index, p_params.op.account.email, sdb);
+    SQL_BIND_TEXT(dpp, email_stmt, index, params->op.account.info.email.c_str(), sdb);
+  } else { // by default by account_id
+    SQL_BIND_INDEX(dpp, stmt, index, p_params.op.account.account_id, sdb);
+    SQL_BIND_TEXT(dpp, stmt, index, params->op.account.info.id.c_str(), sdb);
+  }
+
+out:
+  return rc;
+}
+
+int SQLGetAccount::Execute(const DoutPrefixProvider *dpp, struct DBOpParams *params)
+{
+  int ret = -1;
+
+  if (params->op.query_str == "name") { 
+    SQL_EXECUTE(dpp, params, name_stmt, list_account);
+  } else if (params->op.query_str == "email") { 
+    SQL_EXECUTE(dpp, params, email_stmt, list_account);
+  } else { // by default by account_id
+    SQL_EXECUTE(dpp, params, stmt, list_account);
+  }
+
+out:
+  return ret;
+}
+
 int SQLInsertUser::Prepare(const DoutPrefixProvider *dpp, struct DBOpParams *params)
 {
   int ret = -1;
index acc64e7f5ea8b446d32d671806c47e3f9294ff7b..342224d161411645d73a34e1c0bc47f7c9d19126 100644 (file)
@@ -45,6 +45,7 @@ class SQLiteDB : public DB, virtual public DBOp {
     /* default value matches with sqliteDB style */
 
     int createTables(const DoutPrefixProvider *dpp) override;
+    int createAccountTable(const DoutPrefixProvider *dpp, DBOpParams *params);
     int createBucketTable(const DoutPrefixProvider *dpp, DBOpParams *params);
     int createUserTable(const DoutPrefixProvider *dpp, DBOpParams *params);
     int createObjectTable(const DoutPrefixProvider *dpp, DBOpParams *params);
@@ -58,6 +59,7 @@ class SQLiteDB : public DB, virtual public DBOp {
 
     int createLCTables(const DoutPrefixProvider *dpp) override;
 
+    int DeleteAccountTable(const DoutPrefixProvider *dpp, DBOpParams *params);
     int DeleteBucketTable(const DoutPrefixProvider *dpp, DBOpParams *params);
     int DeleteUserTable(const DoutPrefixProvider *dpp, DBOpParams *params);
     int DeleteObjectTable(const DoutPrefixProvider *dpp, DBOpParams *params);
@@ -83,6 +85,60 @@ class SQLObjectOp : public ObjectOp {
     int InitializeObjectOps(std::string db_name, const DoutPrefixProvider *dpp);
 };
 
+class SQLInsertAccount : public SQLiteDB, public InsertAccountOp {
+  private:
+    sqlite3 **sdb = NULL;
+    sqlite3_stmt *stmt = NULL; // Prepared statement
+
+  public:
+    SQLInsertAccount(void **db, std::string db_name, CephContext *cct) : SQLiteDB((sqlite3 *)(*db), db_name, cct), sdb((sqlite3 **)db) {}
+    ~SQLInsertAccount() {
+      if (stmt)
+        sqlite3_finalize(stmt);
+    }
+    int Prepare(const DoutPrefixProvider *dpp, DBOpParams *params);
+    int Execute(const DoutPrefixProvider *dpp, DBOpParams *params);
+    int Bind(const DoutPrefixProvider *dpp, DBOpParams *params);
+};
+
+class SQLRemoveAccount : public SQLiteDB, public RemoveAccountOp {
+  private:
+    sqlite3 **sdb = NULL;
+    sqlite3_stmt *stmt = NULL; // Prepared statement
+
+  public:
+    SQLRemoveAccount(void **db, std::string db_name, CephContext *cct) : SQLiteDB((sqlite3 *)(*db), db_name, cct), sdb((sqlite3 **)db) {}
+    ~SQLRemoveAccount() {
+      if (stmt)
+        sqlite3_finalize(stmt);
+    }
+    int Prepare(const DoutPrefixProvider *dpp, DBOpParams *params);
+    int Execute(const DoutPrefixProvider *dpp, DBOpParams *params);
+    int Bind(const DoutPrefixProvider *dpp, DBOpParams *params);
+};
+
+class SQLGetAccount : public SQLiteDB, public GetAccountOp {
+  private:
+    sqlite3 **sdb = NULL;
+    sqlite3_stmt *stmt = NULL; // Prepared statement
+    sqlite3_stmt *name_stmt = NULL; // Prepared statement to query by account name
+    sqlite3_stmt *email_stmt = NULL; // Prepared statement to query by email
+
+  public:
+    SQLGetAccount(void **db, std::string db_name, CephContext *cct) : SQLiteDB((sqlite3 *)(*db), db_name, cct), sdb((sqlite3 **)db) {}
+    ~SQLGetAccount() {
+      if (stmt)
+        sqlite3_finalize(stmt);
+      if (name_stmt)
+        sqlite3_finalize(name_stmt);
+      if (email_stmt)
+        sqlite3_finalize(email_stmt);
+    }
+    int Prepare(const DoutPrefixProvider *dpp, DBOpParams *params);
+    int Execute(const DoutPrefixProvider *dpp, DBOpParams *params);
+    int Bind(const DoutPrefixProvider *dpp, DBOpParams *params);
+};
+
 class SQLInsertUser : public SQLiteDB, public InsertUserOp {
   private:
     sqlite3 **sdb = NULL;
index e56697d25b24051917676bb2c34833fbeaadb763..bbbe69917d6f9886ca22fcbc818c1139858b6dfd 100644 (file)
@@ -108,5 +108,76 @@ int POSIXUserDB::Destroy(const DoutPrefixProvider *dpp)
   return 0;
 }
 
+int POSIXAccountDB::ProcessOp(const DoutPrefixProvider *dpp, string_view Op, DBOpParams *params) {
+  int ret = -1;
+  shared_ptr<class DBOp> db_op;
+
+  db_op = getDBOp(dpp, Op, params);
+
+  if (!db_op) {
+    ldpp_dout(dpp, 0)<<"No db_op found for Op("<<Op<<")" << dendl;
+    return ret;
+  }
+  ret = db_op->Execute(dpp, params);
+
+  if (ret) {
+    ldpp_dout(dpp, 0)<<"In Process op Execute failed for fop(" << Op << ")" << dendl;
+  } else {
+    ldpp_dout(dpp, 20)<<"Successfully processed fop(" << Op << ")" << dendl;
+  }
+
+  return ret;
+}
+
+int POSIXAccountDB::Initialize(string logfile, int loglevel)
+{
+  int ret = -1;
+  const DoutPrefixProvider *dpp = get_def_dpp();
+
+  if (!cct) {
+    cout << "Failed to Initialize. No ceph Context \n";
+    return -1;
+  }
+
+  if (loglevel > 0) {
+    cct->_conf->subsys.set_log_level(ceph_subsys_rgw, loglevel);
+  }
+  if (!logfile.empty()) {
+    cct->_log->set_log_file(logfile);
+    cct->_log->reopen_log_file();
+  }
+
+  db = openDB(dpp);
+
+  if (!db) {
+    ldpp_dout(dpp, 0) <<"Failed to open database " << dendl;
+    return ret;
+  }
+
+  ret = InitializeDBOps(dpp);
+
+  if (ret) {
+    ldpp_dout(dpp, 0) <<"InitializePOSIXAccountDBOps failed " << dendl;
+    closeDB(dpp);
+    db = NULL;
+    return ret;
+  }
+
+  ldpp_dout(dpp, 0) << "POSIXAccountDB successfully initialized - name:" \
+    << db_name << "" << dendl;
+
+  return ret;
+}
+
+int POSIXAccountDB::Destroy(const DoutPrefixProvider *dpp)
+{
+  DB::Destroy(dpp);
+
+  ldpp_dout(dpp, 20)<<"POSIXAccountDB successfully destroyed - name:" \
+    <<db_name << dendl;
+
+  return 0;
+}
+
 } } // namespace rgw::store
 
index 7606809948e414bcdec1691aeccfabf863be662c..31ebc96715f7760c220f84efc3472e45d78f93da 100644 (file)
@@ -28,6 +28,9 @@
 namespace rgw { namespace store {
 
 class POSIXUserDB;
+class POSIXAccountDB;
+
+struct POSIXAccountDBOpAccountInfo : DBOpAccountInfo {};
 
 struct POSIXUserDBOpUserInfo : DBOpUserInfo {};
 
@@ -39,6 +42,52 @@ struct POSIXUserDBOpPrepareInfo : DBOpPrepareInfo {};
 
 struct POSIXUserDBOpPrepareParams : DBOpPrepareParams {};
 
+struct POSIXAccountDBOpInfo : DBOpInfo {};
+
+struct POSIXAccountDBOpPrepareInfo : DBOpPrepareInfo {};
+
+struct POSIXAccountDBOpPrepareParams : DBOpPrepareParams {};
+
+struct POSIXAccountDBOps : DBOps {};
+
+class POSIXAccountDBOp : public DBOp {
+  private:
+    static constexpr std::string_view CreateAccountTableQ =
+      /* Corresponds to RGWAccountInfo
+       *
+       * AccountID is made Primary key.
+       * If multiple tenants are stored in single .db handle, should
+       * make both (AccountID, Tenant) as Primary Key.
+       *
+       * XXX:
+       * - Quota stored as blob .. should be linked to quota table.
+       */
+      "CREATE TABLE IF NOT EXISTS '{}' (       \
+      AccountID TEXT NOT NULL UNIQUE,          \
+      Tenant TEXT ,            \
+      AccountName TEXT , \
+      Email TEXT ,     \
+      Quota BLOB ,     \
+      BucketQuota BLOB ,       \
+      MaxUsers INTEGER ,       \
+      MaxRoles INTEGER ,       \
+      MaxGroups INTEGER ,      \
+      MaxBuckets INTEGER ,     \
+      MaxAccessKeys INTEGER ,  \
+      PRIMARY KEY (AccountID) \n);";
+
+  public:
+    POSIXAccountDBOp() : DBOp() {}
+    virtual ~POSIXAccountDBOp() {}
+    std::mutex mtx; // to protect prepared stmt
+};
+
+class InsertPOSIXAccountOp : public SQLInsertAccount {};
+
+class RemovePOSIXAccountOp: public SQLRemoveAccount {};
+
+class GetPOSIXAccountOp: public SQLGetAccount {};
+
 struct POSIXUserDBOps : DBOps {};
 
 class POSIXUserDBOp : public DBOp {
@@ -145,4 +194,51 @@ class POSIXUserDB : public SQLiteDB {
     virtual int ListAllObjects(const DoutPrefixProvider *dpp, DBOpParams *params) override { return 0; }
 };
 
+class POSIXAccountDB : public SQLiteDB {
+  private:
+    const std::string db_name;
+    const std::string account_table;
+    const std::string user_table;
+    const std::string bucket_table;
+    const std::string quota_table;
+    const std::string lc_head_table;
+    const std::string lc_entry_table;
+
+    rgw::sal::Driver* driver;
+
+  protected:
+    void *db;
+    CephContext *cct;
+    const DoutPrefix dp;
+    // Below mutex is to protect objectmap and other shared
+    // objects if any.
+    std::mutex mtx;
+
+  public:
+    struct DBOps dbops;
+
+    POSIXAccountDB(std::string db_name, CephContext *_cct) : SQLiteDB(db_name, _cct),
+               db_name(db_name),
+               account_table(db_name+"_account_table"),
+               user_table(db_name+"_user_table"),
+               cct(_cct),
+               dp(_cct, ceph_subsys_rgw, "rgw POSIXAccountDBStore backend: ")
+                { DB::set_context(cct); }
+
+    int Initialize(std::string logfile, int loglevel);
+    int ProcessOp(const DoutPrefixProvider *dpp, std::string_view Op, DBOpParams *params);
+    int Destroy(const DoutPrefixProvider *dpp);
+
+    CephContext* ctx() { return this->cct; }
+
+    virtual int InitPrepareParams(const DoutPrefixProvider *dpp,
+                                  DBOpPrepareParams &p_params,
+                                  DBOpParams* params) override { return 0; }
+    virtual int createLCTables(const DoutPrefixProvider *dpp) override { return 0; }
+
+    virtual int ListAllBuckets(const DoutPrefixProvider *dpp, DBOpParams *params) override { return 0; }
+    virtual int ListAllUsers(const DoutPrefixProvider *dpp, DBOpParams *params) override { return 0; }
+    virtual int ListAllObjects(const DoutPrefixProvider *dpp, DBOpParams *params) override { return 0; }
+};
+
 } } // namespace rgw::store
index 0299404f65c35d81055a79dcfd1834a695eed918..c1cb6a7a0e80c2eacf1d7e849073782d4d7aa1c0 100644 (file)
@@ -2034,6 +2034,94 @@ int POSIXDriver::get_user_by_swift(const DoutPrefixProvider* dpp, const std::str
   return -ENOTSUP;
 }
 
+int POSIXDriver::load_account_by_id(const DoutPrefixProvider* dpp,
+                                optional_yield y,
+                                std::string_view id,
+                                RGWAccountInfo& info,
+                                Attrs& attrs,
+                                RGWObjVersionTracker& objv)
+{
+  RGWObjVersionTracker objv_tracker;
+
+  int ret = accountDB->get_account(dpp, std::string("account_id"), std::string(id), info, &attrs,
+      &objv_tracker);
+
+  if (ret < 0)
+    return ret;
+
+  objv = objv_tracker;
+  return 0;
+}
+
+int POSIXDriver::load_account_by_name(const DoutPrefixProvider* dpp,
+                                optional_yield y,
+                                std::string_view tenant,
+                                std::string_view name,
+                                RGWAccountInfo& info,
+                                Attrs& attrs,
+                                RGWObjVersionTracker& objv)
+{
+  RGWObjVersionTracker objv_tracker;
+
+  int ret = accountDB->get_account(dpp, std::string("name"), std::string(name), info, &attrs,
+      &objv_tracker);
+
+  if (ret < 0)
+    return ret;
+
+  objv = objv_tracker;
+  return 0;
+}
+
+int POSIXDriver::load_account_by_email(const DoutPrefixProvider* dpp,
+                                 optional_yield y,
+                                 std::string_view email,
+                                 RGWAccountInfo& info,
+                                 Attrs& attrs,
+                                 RGWObjVersionTracker& objv)
+{
+  RGWObjVersionTracker objv_tracker;
+
+  int ret = accountDB->get_account(dpp, std::string("email"), std::string(email), info, &attrs,
+      &objv_tracker);
+
+  if (ret < 0)
+    return ret;
+
+  objv = objv_tracker;
+  return 0;
+}
+
+int POSIXDriver::store_account(const DoutPrefixProvider* dpp,
+                         optional_yield y, bool exclusive,
+                         const RGWAccountInfo& info,
+                         const RGWAccountInfo* old_info,
+                         const Attrs& attrs,
+                         RGWObjVersionTracker& objv)
+{
+  int ret = accountDB->store_account(dpp, info, exclusive, &attrs, &objv);
+
+  if (ret < 0)
+    return ret;
+
+  return 0;
+}
+
+int POSIXDriver::delete_account(const DoutPrefixProvider* dpp,
+                            optional_yield y,
+                            const RGWAccountInfo& info,
+                            RGWObjVersionTracker& objv)
+{
+  int ret = accountDB->remove_account(dpp, info, &objv);
+
+  if (ret < 0)
+    return ret;
+
+  return 0;
+}
+
+
+
 int POSIXDriver::load_owner_by_email(const DoutPrefixProvider* dpp,
                                    optional_yield y,
                                    std::string_view email,
index 4edc8b13abe5a6f663adbb56d6d119bb6e0e5b77..32e8c085a0f400c67457de3d064a5ae5529c06db 100644 (file)
@@ -475,6 +475,7 @@ class POSIXDriver : public StoreDriver {
 protected:     
   CephContext *cct;
   std::unique_ptr<rgw::store::POSIXUserDB> userDB;
+  std::unique_ptr<rgw::store::POSIXAccountDB> accountDB;
   POSIXZone zone;
   std::unique_ptr<BucketCache> bucket_cache;
   std::string base_path;
@@ -491,6 +492,7 @@ public:
     auto db_full_path = std::filesystem::path(db_path) / db_name;
     
     userDB = std::make_unique<rgw::store::POSIXUserDB>(db_full_path.string(), cct);
+    accountDB = std::make_unique<rgw::store::POSIXAccountDB>(db_full_path.string(), cct);
   }
   virtual ~POSIXDriver() { }
 
@@ -518,32 +520,32 @@ public:
                                 std::string_view id,
                                 RGWAccountInfo& info,
                                 Attrs& attrs,
-                                RGWObjVersionTracker& objv) override { return -ENOTSUP; }
+                                RGWObjVersionTracker& objv) override;
   virtual int load_account_by_name(const DoutPrefixProvider* dpp,
                                 optional_yield y,
                                 std::string_view tenant,
                                 std::string_view name,
                                 RGWAccountInfo& info,
                                 Attrs& attrs,
-                                RGWObjVersionTracker& objv) override { return -ENOTSUP; }
+                                RGWObjVersionTracker& objv) override;
   virtual int load_account_by_email(const DoutPrefixProvider* dpp,
                                  optional_yield y,
                                  std::string_view email,
                                  RGWAccountInfo& info,
                                  Attrs& attrs,
-                                 RGWObjVersionTracker& objv) override { return -ENOTSUP; }
+                                 RGWObjVersionTracker& objv) override;
 
   virtual int store_account(const DoutPrefixProvider* dpp,
                          optional_yield y, bool exclusive,
                          const RGWAccountInfo& info,
                          const RGWAccountInfo* old_info,
                          const Attrs& attrs,
-                         RGWObjVersionTracker& objv) override { return -ENOTSUP; }
+                         RGWObjVersionTracker& objv) override;
 
   virtual int delete_account(const DoutPrefixProvider* dpp,
                             optional_yield y,
                             const RGWAccountInfo& info,
-                            RGWObjVersionTracker& objv) override { return -ENOTSUP; }
+                            RGWObjVersionTracker& objv) override;
 
   virtual int load_stats(const DoutPrefixProvider* dpp,
                         optional_yield y,