Skip to content

Commit

Permalink
#163 new config option rados_check_empty_mailboxes = true|false new d…
Browse files Browse the repository at this point in the history
…oveadm rmb mailbox delete cmd
  • Loading branch information
jrse committed Jun 27, 2018
1 parent 3e5c522 commit 0390143
Show file tree
Hide file tree
Showing 10 changed files with 239 additions and 6 deletions.
3 changes: 2 additions & 1 deletion src/librmb/rados-dovecot-ceph-cfg-impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class RadosDovecotCephCfgImpl : public RadosDovecotCephCfg {

std::string &get_key_prefix_keywords() override { return dovecot_cfg.get_key_prefix_keywords(); }
void update_metadata(const std::string &key, const char *value_) override { dovecot_cfg.update_metadata(key, value_); }

bool is_rbox_check_empty_mailboxes() override { return dovecot_cfg.is_rbox_check_empty_mailboxes(); }
bool is_ceph_posix_bugfix_enabled() override { return dovecot_cfg.is_ceph_posix_bugfix_enabled(); }
// rados config
bool is_user_mapping() override { return rados_cfg.is_user_mapping(); }
Expand Down Expand Up @@ -93,6 +93,7 @@ class RadosDovecotCephCfgImpl : public RadosDovecotCephCfg {
int save_object(const std::string &oid, librados::bufferlist &buffer) override { return rados_cfg.save_object(oid, buffer); }
int read_object(const std::string &oid, librados::bufferlist *buffer) override { return rados_cfg.read_object(oid, buffer); }
void set_io_ctx_namespace(const std::string &namespace_) override { rados_cfg.set_io_ctx_namespace(namespace_); }

RadosConfig *get_dovecot_cfg() { return &dovecot_cfg; }
RadosCephConfig *get_rados_ceph_cfg() { return &rados_cfg; }

Expand Down
1 change: 1 addition & 0 deletions src/librmb/rados-dovecot-ceph-cfg.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ class RadosDovecotCephCfg {
virtual int save_object(const std::string &oid, librados::bufferlist &buffer) = 0;
virtual int read_object(const std::string &oid, librados::bufferlist *buffer) = 0;
virtual void set_io_ctx_namespace(const std::string &namespace_) = 0;
virtual bool is_rbox_check_empty_mailboxes() = 0;
};

} /* namespace librmb */
Expand Down
5 changes: 4 additions & 1 deletion src/librmb/rados-dovecot-config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,16 @@ RadosConfig::RadosConfig()
rados_username("rados_user_name"),
prefix_keyword("k"),
bugfix_cephfs_posix_hardlinks("rbox_bugfix_cephfs_21652"),
save_log("rados_save_log") {
save_log("rados_save_log"),
rbox_check_empty_mailboxes("rados_check_empty_mailboxes") {
config[pool_name] = "mail_storage";

config[rbox_cfg_object_name] = "rbox_cfg";
config[rbox_cluster_name] = "ceph";
config[rados_username] = "client.admin";
config[bugfix_cephfs_posix_hardlinks] = "false";
config[save_log] = "";
config[rbox_check_empty_mailboxes] = "false";
is_valid = false;
}

Expand Down Expand Up @@ -65,6 +67,7 @@ std::string RadosConfig::to_string() {
ss << " " << rados_username << "=" << config[rados_username] << std::endl;
ss << " " << bugfix_cephfs_posix_hardlinks << "=" << config[bugfix_cephfs_posix_hardlinks] << std::endl;
ss << " " << save_log << "=" << config[save_log] << std::endl;
ss << " " << rbox_check_empty_mailboxes << "=" << config[rbox_check_empty_mailboxes] << std::endl;
return ss.str();
}

Expand Down
5 changes: 4 additions & 1 deletion src/librmb/rados-dovecot-config.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ class RadosConfig {
return config[bugfix_cephfs_posix_hardlinks].compare("true") == 0 ? true : false;
}
void set_rbox_cfg_object_name(const std::string &value) { config[rbox_cfg_object_name] = value; }

bool is_rbox_check_empty_mailboxes() {
return config[rbox_check_empty_mailboxes].compare("true") == 0 ? true : false;
}
std::string to_string();

private:
Expand All @@ -62,6 +64,7 @@ class RadosConfig {
std::string prefix_keyword;
std::string bugfix_cephfs_posix_hardlinks;
std::string save_log;
std::string rbox_check_empty_mailboxes;
bool is_valid;
};

Expand Down
139 changes: 139 additions & 0 deletions src/storage-rbox/doveadm-rbox-plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ extern "C" {
#include "mail-search-parser-private.h"
#include "mail-search.h"
#include "mail-search-build.h"
#include "doveadm-cmd.h"
#include "doveadm-mail.h"
#include "istream.h"
#include "doveadm-print.h"
}
#include "tools/rmb/rmb-commands.h"
#include "rados-cluster.h"
Expand All @@ -34,8 +38,11 @@ extern "C" {
#include "rados-storage-impl.h"
#include "rados-dovecot-ceph-cfg.h"
#include "rados-dovecot-ceph-cfg-impl.h"
#include "rados-namespace-manager.h"
#include "rbox-storage.h"
#include "rbox-save.h"
#include "rbox-storage.hpp"

#include <algorithm>

class RboxDoveadmPlugin {
Expand Down Expand Up @@ -724,6 +731,106 @@ static int cmd_rmb_check_indices_run(struct doveadm_mail_cmd_context *ctx, struc
return ret;
}

struct delete_cmd_context {
struct doveadm_mail_cmd_context ctx;
bool recursive;
int argc;
char **argv;
};

static int cmd_rmb_mailbox_delete_run(struct doveadm_mail_cmd_context *ctx, struct mail_user *user) {
i_debug("wrapping doveadm mailbox delete command");
const struct doveadm_mail_cmd *cmd;
const char *error;
const char *cmd_name = "mailbox delete";
int ret = 0;
cmd = doveadm_mail_cmd_find(cmd_name);
if (cmd != NULL) {
i_debug("found a acommand");
}

struct delete_cmd_context *ctx_ = (struct delete_cmd_context *)ctx;

struct doveadm_mail_cmd_context *mail_delete_ctx = doveadm_mail_cmd_init(cmd, doveadm_settings);
mail_delete_ctx->full_args = ctx->full_args;
/* keep context's getopt_args first in case it contains '+' */
mail_delete_ctx->getopt_args = ctx->getopt_args;
mail_delete_ctx->cur_username = ctx->cur_username;
mail_delete_ctx->service_flags = ctx->service_flags;
mail_delete_ctx->args = ctx->args;
if (mail_delete_ctx->v.preinit != NULL)
mail_delete_ctx->v.preinit(ctx);

mail_delete_ctx->iterate_single_user = ctx->iterate_single_user;
// only support single user
if (ctx->iterate_single_user) {
struct mail_storage_service_input input;
memset(&input, 0, sizeof(input));
input.service = "doveadm";
input.username = mail_delete_ctx->cur_username;
mail_delete_ctx->cur_client_ip = ctx->cur_client_ip;
mail_delete_ctx->storage_service_input = input;
mail_delete_ctx->storage_service = ctx->storage_service;
mail_delete_ctx->cur_mail_user = ctx->cur_mail_user;
mail_delete_ctx->cur_service_user = ctx->cur_service_user;
mail_delete_ctx->v.init(mail_delete_ctx, mail_delete_ctx->args);

if (mail_delete_ctx->v.prerun != NULL) {
if (mail_delete_ctx->v.prerun(mail_delete_ctx, mail_delete_ctx->cur_service_user, &error) < 0) {
return -1;
}
}
if (mail_delete_ctx->v.run(mail_delete_ctx, mail_delete_ctx->cur_mail_user) < 0) {
i_assert(mail_delete_ctx->exit_code != 0);
}
// success!

// cleanup}
doveadm_mail_server_flush();
mail_delete_ctx->v.deinit(ctx);
doveadm_print_flush();

if (mail_delete_ctx->users_list_input != NULL)
i_stream_unref(&mail_delete_ctx->users_list_input);
if (mail_delete_ctx->cmd_input != NULL)
i_stream_unref(&mail_delete_ctx->cmd_input);

} else {
i_debug("bad we only support single user mailbox delete");
return -1;
}

i_debug("cleaning up rbox specific files and objects :ret=%d", ret);
if (ctx_->recursive) {
i_debug("recursive option set, freeing indirect object if existend");

RboxDoveadmPlugin plugin;
plugin.read_plugin_configuration(user);
int open = open_connection_load_config(&plugin, user);
if (open < 0) {
i_error("error opening rados connection, check config: %d", open);
return open;
}
std::map<std::string, std::string> opts;
opts["namespace"] = user->username;
librmb::RmbCommands rmb_cmds(plugin.storage, plugin.cluster, &opts);

std::string uid;
librmb::RadosCephConfig *cfg =
(static_cast<librmb::RadosDovecotCephCfgImpl *>(plugin.config))->get_rados_ceph_cfg();
librmb::RadosStorageMetadataModule *ms = rmb_cmds.init_metadata_storage_module(*cfg, &uid);

if (cfg->is_user_mapping()) {
// we need to delete the namespace object.
// iterate over all mailboxes, if we have no more mails, delete the user namespace object
// for the current user.
librmb::RadosNamespaceManager mgr(plugin.config);
check_users_mailbox_delete_ns_object(user, plugin.config, &mgr, plugin.storage);
}
}
return 0;
}

static void cmd_rmb_lspools_init(struct doveadm_mail_cmd_context *ctx ATTR_UNUSED, const char *const args[]) {
if (str_array_length(args) > 0) {
doveadm_mail_help_name("rmb lspools");
Expand Down Expand Up @@ -775,6 +882,15 @@ static void cmd_rmb_check_indices_init(struct doveadm_mail_cmd_context *ctx ATTR
doveadm_mail_help_name("rmb check indices");
}
}
static void cmd_rmb_mailbox_delete_init(struct doveadm_mail_cmd_context *ctx ATTR_UNUSED, const char *const args[]) {
i_debug("ok");
/*if (str_array_length(args) > 1) {
doveadm_mail_help_name("rmb mailbox delete");
}*/
struct delete_cmd_context *ctx_ = (struct delete_cmd_context *)ctx;

// ctx_->argv = &args;
}
struct doveadm_mail_cmd_context *cmd_rmb_lspools_alloc(void) {
struct doveadm_mail_cmd_context *ctx;
ctx = doveadm_mail_cmd_alloc(struct doveadm_mail_cmd_context);
Expand Down Expand Up @@ -861,3 +977,26 @@ struct doveadm_mail_cmd_context *cmd_rmb_check_indices_alloc(void) {
ctx->v.init = cmd_rmb_check_indices_init;
return ctx;
}

static bool cmd_mailbox_delete_parse_arg(struct doveadm_mail_cmd_context *_ctx, int c) {
struct delete_cmd_context *ctx = (struct delete_cmd_context *)_ctx;

switch (c) {
case 'r':
ctx->recursive = TRUE;
break;
default:
return TRUE;
}
return TRUE;
}

struct doveadm_mail_cmd_context *cmd_rmb_mailbox_delete_alloc(void) {
struct delete_cmd_context *ctx;
ctx = doveadm_mail_cmd_alloc(struct delete_cmd_context);
ctx->ctx.v.run = cmd_rmb_mailbox_delete_run;
ctx->ctx.v.init = cmd_rmb_mailbox_delete_init;
ctx->ctx.v.parse_arg = cmd_mailbox_delete_parse_arg;
ctx->ctx.getopt_args = "rs";
return &ctx->ctx;
}
1 change: 1 addition & 0 deletions src/storage-rbox/doveadm-rbox-plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ extern struct doveadm_mail_cmd_context *cmd_rmb_ls_mb_alloc(void);
extern struct doveadm_mail_cmd_context *cmd_rmb_rename_alloc(void);
extern struct doveadm_mail_cmd_context *cmd_rmb_save_log_alloc(void);
extern struct doveadm_mail_cmd_context *cmd_rmb_check_indices_alloc(void);
extern struct doveadm_mail_cmd_context *cmd_rmb_mailbox_delete_alloc(void);

#endif // SRC_DOVEADM_RBOX_PLUGIN_H_
3 changes: 2 additions & 1 deletion src/storage-rbox/doveadm-rbox.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ static struct doveadm_mail_cmd rmb_commands[] = {
{cmd_rmb_ls_mb_alloc, "rmb ls mb", NULL},
{cmd_rmb_rename_alloc, "rmb rename", "new username"},
{cmd_rmb_save_log_alloc, "rmb save_log", "path to save_log"},
{cmd_rmb_check_indices_alloc, "rmb check indices", "delete_not_referenced_objects"}};
{cmd_rmb_check_indices_alloc, "rmb check indices", "delete_not_referenced_objects"},
{cmd_rmb_mailbox_delete_alloc, "rmb mailbox delete", "[-r] <mailbox> [...]"}};

void doveadm_rbox_plugin_init(struct module *module ATTR_UNUSED) {
unsigned int i;
Expand Down
83 changes: 82 additions & 1 deletion src/storage-rbox/rbox-storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,87 @@ void rbox_notify_changes(struct mailbox *box) {
FUNC_END();
}

int check_users_mailbox_delete_ns_object(struct mail_user *user, librmb::RadosDovecotCephCfg *config,
librmb::RadosNamespaceManager *ns_mgr, librmb::RadosStorage *storage) {
int ret = 0;
struct mail_namespace *ns = mail_namespace_find_inbox(user->namespaces);
for (; ns != NULL; ns = ns->next) {
struct mailbox_list_iterate_context *iter;
const struct mailbox_info *info;
iter = mailbox_list_iter_init(ns->list, "*", static_cast<enum mailbox_list_iter_flags>(
MAILBOX_LIST_ITER_RAW_LIST | MAILBOX_LIST_ITER_RETURN_NO_FLAGS));

int total_mails = 0;
while ((info = mailbox_list_iter_next(iter)) != NULL) {
if ((info->flags & (MAILBOX_NONEXISTENT | MAILBOX_NOSELECT)) == 0) {
struct mailbox *box_ = mailbox_alloc(ns->list, info->vname, MAILBOX_FLAG_IGNORE_ACLS);
struct mailbox_status status;
if (mailbox_get_status(box_, STATUS_MESSAGES, &status) < 0) {
i_error("cannot get status of %s", info->vname);
++total_mails; // make sure we do not delete anything due to invalid status query!!!
} else {
i_debug("mailbox %s, has %d messages", info->vname, status.messages);
std::cout << "mailbox " << info->vname << " has " << status.messages << " messages" << std::endl;
total_mails += status.messages;
}
mailbox_free(&box_);
}
}
if (mailbox_list_iter_deinit(&iter) < 0)
ret = -1;

if (total_mails == 0) {
std::string uid = ns->owner->username;
uid += config->get_user_suffix();
std::string ns_str;
ns_mgr->lookup_key(uid, &ns_str);
i_debug(
"total number of mails in all mailboxes is %d, deleting indirect namespace object for user %s with "
"namespace: %s ",
total_mails, uid.c_str(), ns_str.c_str());
storage->set_namespace(config->get_user_ns());
ret = storage->delete_mail(uid);
if (ret < 0) {
if (ret == -2) {
i_debug("indirect ns object already deleted %d", ret);
} else {
i_error("Error deleting ns object %d", ret);
}
}
}
}
return ret;
}

int rbox_storage_mailbox_delete(struct mailbox *box) {
FUNC_START();
int ret = index_storage_mailbox_delete(box);
if (ret < 0) {
i_error("while processing index_storage_mailbox_delete: %d", ret);
return ret;
}
struct rbox_storage *storage = (struct rbox_storage *)box->storage;
// 90 plugin konfigurierbar!
read_plugin_configuration(box);
if (!storage->config->is_rbox_check_empty_mailboxes()) {
return ret;
}

ret = rbox_open_rados_connection(box, false);
if (ret < 0) {
i_error("Opening rados connection : %d", ret);
return ret;
}
if (storage->config->is_user_mapping()) { //

struct rbox_mailbox *mbox = (struct rbox_mailbox *)box;
ret =
check_users_mailbox_delete_ns_object(mbox->storage->storage.user, storage->config, storage->ns_mgr, storage->s);
}
FUNC_END();
return ret;
}

struct mailbox_vfuncs rbox_mailbox_vfuncs = {index_storage_is_readonly,
index_storage_mailbox_enable,
index_storage_mailbox_exists,
Expand All @@ -769,7 +850,7 @@ struct mailbox_vfuncs rbox_mailbox_vfuncs = {index_storage_is_readonly,
index_storage_mailbox_free,
rbox_mailbox_create,
rbox_mailbox_update,
index_storage_mailbox_delete,
rbox_storage_mailbox_delete,
index_storage_mailbox_rename,
index_storage_get_status,
rbox_mailbox_get_metadata,
Expand Down
3 changes: 2 additions & 1 deletion src/storage-rbox/rbox-storage.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ extern int rbox_read_header(struct rbox_mailbox *mbox, struct sdbox_index_header

extern int rbox_mailbox_create_indexes(struct mailbox *box, const struct mailbox_update *update,
struct mail_index_transaction *trans);

extern int check_users_mailbox_delete_ns_object(struct mail_user *user, librmb::RadosDovecotCephCfg *config,
librmb::RadosNamespaceManager *ns_mgr, librmb::RadosStorage *storage);
/*
struct mail_save_context *rbox_save_alloc(struct mailbox_transaction_context *_t);
int rbox_save_begin(struct mail_save_context *ctx, struct istream *input);
Expand Down
2 changes: 2 additions & 0 deletions src/tests/mocks/mock_test.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,8 @@ class RadosDovecotCephCfgMock : public RadosDovecotCephCfg {
MOCK_METHOD1(set_io_ctx_namespace, void(const std::string &namespace_));
MOCK_METHOD0(get_metadata_storage_module, std::string &());
MOCK_METHOD0(get_metadata_storage_attribute, std::string &());

MOCK_METHOD0(is_rbox_check_empty_mailboxes, bool());
};

} // namespace librmbtest
Expand Down

0 comments on commit 0390143

Please sign in to comment.