From 640bbf17994f859d98b7b100615c873a4aa6183d Mon Sep 17 00:00:00 2001 From: Eric Bollengier Date: Mon, 1 Feb 2010 18:08:06 +0100 Subject: [PATCH] Implement new "purge volume action" command to trigg ActionOnPurge. This command will replace the automatic truncate operation when purging the volume. example: *update volume=xxxx actiononpurge=Truncate *purge volume=xxxx *purge volume=xxxx action=all storage=File *purge volume=xxxx action=truncate *purge volume action allpools storage=File --- bacula/src/dird/ua_cmds.c | 2 +- bacula/src/dird/ua_purge.c | 191 ++++++++++++++++++++++++++++--------- 2 files changed, 147 insertions(+), 46 deletions(-) diff --git a/bacula/src/dird/ua_cmds.c b/bacula/src/dird/ua_cmds.c index 2a8ebec0ef..6e93c0267d 100644 --- a/bacula/src/dird/ua_cmds.c +++ b/bacula/src/dird/ua_cmds.c @@ -151,7 +151,7 @@ static struct cmdstruct commands[] = { /* C { NT_("prune"), prunecmd, _("Prune expired records from catalog"), NT_("files | jobs | pool= | client= | volume= "), true}, - { NT_("purge"), purgecmd, _("Purge records from catalog"), NT_("volume="), true}, + { NT_("purge"), purgecmd, _("Purge records from catalog"), NT_("files jobs volume= [action= devicetype= pool= allpools storage= drive=]"), true}, { NT_("python"), python_cmd, _("Python control commands"), NT_(""), false}, { NT_("quit"), quit_cmd, _("Terminate Bconsole session"), NT_(""), false}, { NT_("query"), querycmd, _("Query catalog"), NT_(""), false}, diff --git a/bacula/src/dird/ua_purge.c b/bacula/src/dird/ua_purge.c index c4f0d8ecb0..c78f83a969 100644 --- a/bacula/src/dird/ua_purge.c +++ b/bacula/src/dird/ua_purge.c @@ -44,6 +44,7 @@ /* Forward referenced functions */ static int purge_files_from_client(UAContext *ua, CLIENT *client); static int purge_jobs_from_client(UAContext *ua, CLIENT *client); +static int aop_cmd(UAContext *ua, const char *cmd); static const char *select_jobsfiles_from_client = "SELECT JobId FROM Job " @@ -138,6 +139,11 @@ int purgecmd(UAContext *ua, const char *cmd) } /* Volume */ case 2: + /* Perform ActionOnPurge (action=truncate) */ + if (find_arg(ua, "action") >= 0) { + return aop_cmd(ua, ua->cmd); + } + while ((i=find_arg(ua, NT_("volume"))) >= 0) { if (select_media_dbr(ua, &mr)) { purge_jobs_from_volume(ua, &mr, /*force*/true); @@ -571,14 +577,13 @@ static BSOCK *open_sd_bsock(UAContext *ua) return ua->jcr->store_bsock; } -static void do_actions_on_purge(UAContext *ua, MEDIA_DBR *mr) +static void do_truncate_on_purge(UAContext *ua, MEDIA_DBR *mr, + char *pool, char *storage, + int drive, BSOCK *sd) { - BSOCK *sd; - POOL_DBR pr; - bool ok=false; int dvd; + bool ok=false; uint64_t VolBytes = 0; - char dev_name[MAX_NAME_LENGTH]; /* TODO: Return if not mr->Recyle ? */ if (!mr->Recycle) { @@ -590,59 +595,158 @@ static void do_actions_on_purge(UAContext *ua, MEDIA_DBR *mr) * is disabled for the specific device, this will be a no-op. */ - if ((sd=open_sd_bsock(ua)) != NULL) { - memset(&pr, 0, sizeof(POOL_DBR)); - - pr.PoolId = mr->PoolId; - strcpy(pr.Name, "Default"); /* We don't use the Pool in label */ - bstrncpy(dev_name, ua->jcr->wstore->dev_name(), sizeof(dev_name)); + /* Protect us from spaces */ + bash_spaces(mr->VolumeName); + bash_spaces(mr->MediaType); + bash_spaces(pool); + bash_spaces(storage); - /* Protect us from spaces */ - bash_spaces(dev_name); - bash_spaces(mr->VolumeName); - bash_spaces(mr->MediaType); - bash_spaces(pr.Name); - - /* We set drive=-1 to let the storage decides of which drive - * to use - */ - sd->fsend("relabel %s OldName=%s NewName=%s PoolName=%s " - "MediaType=%s Slot=%d drive=%d\n", - dev_name, + sd->fsend("relabel %s OldName=%s NewName=%s PoolName=%s " + "MediaType=%s Slot=%d drive=%d\n", + storage, mr->VolumeName, mr->VolumeName, - pr.Name, mr->MediaType, mr->Slot, -1); + pool, mr->MediaType, mr->Slot, drive); - unbash_spaces(mr->VolumeName); - unbash_spaces(mr->MediaType); - while (sd->recv() >= 0) { - ua->send_msg("%s", sd->msg); - if (sscanf(sd->msg, "3000 OK label. VolBytes=%llu DVD=%d ", - &VolBytes, &dvd) == 2) - { - ok = true; - } + unbash_spaces(mr->VolumeName); + unbash_spaces(mr->MediaType); + unbash_spaces(pool); + unbash_spaces(storage); + + while (sd->recv() >= 0) { + ua->send_msg("%s", sd->msg); + if (sscanf(sd->msg, "3000 OK label. VolBytes=%llu DVD=%d ", + &VolBytes, &dvd) == 2) + { + ok = true; } - sd->signal(BNET_TERMINATE); - sd->close(); - ua->jcr->store_bsock = NULL; - - } else { - ua->error_msg(_("Could not connect to storage daemon")); } - + if (ok) { mr->VolBytes = VolBytes; mr->VolFiles = 0; if (!db_update_media_record(ua->jcr, ua->db, mr)) { ua->error_msg(_("Can't update volume size in the catalog\n")); } - ua->send_msg(_("The volume has been truncated\n")); + ua->send_msg(_("The volume \"%s\" has been truncated\n"), mr->VolumeName); } else { - ua->warning_msg(_("Unable to truncate the volume\n")); + ua->warning_msg(_("Unable to truncate volume \"%s\"\n"), mr->VolumeName); } } } +/* purge action= pool= volume= storage= devicetype= */ +static int aop_cmd(UAContext *ua, const char *cmd) +{ + bool allpools=false; + int drive=-1; + int nb=0; + + uint32_t *results=NULL; + const char *action="all"; + STORE *store=NULL; + POOL *pool=NULL; + MEDIA_DBR mr; + POOL_DBR pr; + + BSOCK *sd=NULL; + + memset(&pr, 0, sizeof(pr)); + memset(&mr, 0, sizeof(mr)); + + /* Look arguments */ + for (int i=1; iargc; i++) { + if (strcasecmp(ua->argk[i], NT_("allpools")) == 0) { + allpools = true; + + } else if (strcasecmp(ua->argk[i], NT_("volume")) == 0 && ua->argv[i]) { + bstrncpy(mr.VolumeName, ua->argv[i], sizeof(mr.VolumeName)); + + } else if (strcasecmp(ua->argk[i], NT_("devicetype")) == 0 && ua->argv[i]) { + bstrncpy(mr.MediaType, ua->argv[i], sizeof(mr.MediaType)); + + } else if (strcasecmp(ua->argk[i], NT_("drive")) == 0 && ua->argv[i]) { + drive = atoi(ua->argv[i]); + + } else if (strcasecmp(ua->argk[i], NT_("action")) == 0 && ua->argv[i]) { + action=ua->argv[i]; + } + } + + /* Choose storage */ + ua->jcr->wstore = store = get_storage_resource(ua, false); + if (!store) { + goto bail_out; + } + mr.StorageId = store->StorageId; + + if (!open_db(ua)) { + Dmsg0(100, "Can't open db\n"); + goto bail_out; + } + + if (!allpools) { + /* force pool selection */ + pool = get_pool_resource(ua); + if (!pool) { + Dmsg0(100, "Can't get pool resource\n"); + goto bail_out; + } + bstrncpy(pr.Name, pool->name(), sizeof(pr.Name)); + if (!db_get_pool_record(ua->jcr, ua->db, &pr)) { + Dmsg0(100, "Can't get pool record\n"); + goto bail_out; + } + mr.PoolId = pr.PoolId; + } + + mr.Recycle = 1; + mr.Enabled = 1; + mr.VolBytes = 10000; + bstrncpy(mr.VolStatus, "Purged", sizeof(mr.VolStatus)); + + if (!db_get_media_ids(ua->jcr, ua->db, &mr, &nb, &results)) { + Dmsg0(100, "No results from db_get_media_ids\n"); + goto bail_out; + } + + if (!nb) { + ua->send_msg(_("No volume founds to perform %s action(s)\n"), action); + goto bail_out; + } + + if ((sd=open_sd_bsock(ua)) == NULL) { + Dmsg0(100, "Can't open connection to sd\n"); + goto bail_out; + } + + for (int i=0; i < nb; i++) { + memset(&mr, 0, sizeof(mr)); + mr.MediaId = results[i]; + if (db_get_media_record(ua->jcr, ua->db, &mr)) { + /* TODO: ask for drive and change Pool */ + if (!strcasecmp("truncate", action) || !strcasecmp("all", action)) { + do_truncate_on_purge(ua, &mr, pr.Name, store->dev_name(), drive, sd); + } + } else { + Dmsg1(0, "Can't find MediaId=%lld\n", (uint64_t) mr.MediaId); + } + } + +bail_out: + close_db(ua); + if (sd) { + sd->signal(BNET_TERMINATE); + sd->close(); + ua->jcr->store_bsock = NULL; + } + ua->jcr->wstore = NULL; + if (results) { + free(results); + } + + return 1; +} + /* * IF volume status is Append, Full, Used, or Error, mark it Purged * Purged volumes can then be recycled (if enabled). @@ -686,9 +790,6 @@ bool mark_media_purged(UAContext *ua, MEDIA_DBR *mr) ua->error_msg("%s", db_strerror(ua->db)); } } - - /* Do any ActionOnPurge for this Volume */ - do_actions_on_purge(ua, mr); /* Send message to Job report, if it is a *real* job */ if (jcr && jcr->JobId > 0) { -- 2.39.5