diff options
author | Philipp Storz <philipp.storz@bareos.com> | 2022-09-19 13:40:42 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-19 13:40:42 +0300 |
commit | d8277245c29ca8e10d8dfb024739a08a0970d10e (patch) | |
tree | f5eab3d108de071b939c73b61913444e89d88f0a | |
parent | f391ac27328d4e2dfaa94a46b1126f9ae8cc3d86 (diff) | |
parent | 9a68d1c376b4c395c36ff1536370cb2038e80804 (diff) |
Merge pull request #1074
stored: dird: add backup checkpoints that save backup metadata to the Catalog during the execution of the backup
116 files changed, 2047 insertions, 117 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e7a0c95f..629dc225e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,8 @@ and since Bareos version 20 this project adheres to [Semantic Versioning](https: - bareos tools: reintegrate testfind binary [PR #1176] - fd: add support for role switching on PostgreSQL add-on [BUG #4607] [PR #1178] - build: switch from FreeBSD 13.0 to 13.1 [PR #1253] +- stored: dird: added backup checkpoints that save backup metadata to the Catalog during the execution of the backup. [PR#1074] +- stored: dird: add backup checkpoints that save backup metadata to the Catalog during the execution of the backup. [PR #1074] ### Fixed - dird: RunScript fixes [PR #1217] @@ -204,6 +206,7 @@ and since Bareos version 20 this project adheres to [Semantic Versioning](https: [PR #1067]: https://github.com/bareos/bareos/pull/1067 [PR #1070]: https://github.com/bareos/bareos/pull/1070 [PR #1072]: https://github.com/bareos/bareos/pull/1072 +[PR #1074]: https://github.com/bareos/bareos/pull/1074 [PR #1079]: https://github.com/bareos/bareos/pull/1079 [PR #1081]: https://github.com/bareos/bareos/pull/1081 [PR #1082]: https://github.com/bareos/bareos/pull/1082 diff --git a/core/src/cats/cats.h b/core/src/cats/cats.h index acb2034f0..37f6c8fdc 100644 --- a/core/src/cats/cats.h +++ b/core/src/cats/cats.h @@ -893,6 +893,7 @@ class BareosDb : public BareosDbQueryEnum { /* sql_update.c */ bool UpdateJobStartRecord(JobControlRecord* jcr, JobDbRecord* jr); + bool UpdateRunningJobRecord(JobControlRecord* jcr); bool UpdateJobEndRecord(JobControlRecord* jcr, JobDbRecord* jr); bool UpdateClientRecord(JobControlRecord* jcr, ClientDbRecord* cr); bool UpdatePoolRecord(JobControlRecord* jcr, PoolDbRecord* pr); diff --git a/core/src/cats/sql_create.cc b/core/src/cats/sql_create.cc index fd4c291e7..3d26ceba9 100644 --- a/core/src/cats/sql_create.cc +++ b/core/src/cats/sql_create.cc @@ -3,7 +3,7 @@ Copyright (C) 2000-2012 Free Software Foundation Europe e.V. Copyright (C) 2011-2016 Planets Communications B.V. - Copyright (C) 2013-2020 Bareos GmbH & Co. KG + Copyright (C) 2013-2022 Bareos GmbH & Co. KG This program is Free Software; you can redistribute it and/or modify it under the terms of version three of the GNU Affero General Public @@ -107,31 +107,58 @@ bool BareosDb::CreateJobmediaRecord(JobControlRecord* jcr, JobMediaDbRecord* jm) DbLocker _{this}; - Mmsg(cmd, "SELECT count(*) from JobMedia WHERE JobId=%s", - edit_int64(jm->JobId, ed1)); - count = GetSqlRecordMax(jcr); - if (count < 0) { count = 0; } - count++; - /* clang-format off */ Mmsg(cmd, - "INSERT INTO JobMedia (JobId,MediaId,FirstIndex,LastIndex," - "StartFile,EndFile,StartBlock,EndBlock,VolIndex,JobBytes) " - "VALUES (%s,%s,%u,%u,%u,%u,%u,%u,%u,%s)", + "UPDATE JobMedia SET LastIndex=%lu, EndFile=%lu, EndBlock=%lu, JobBytes=%s " + "WHERE JobId=%s AND MediaId=%s", + jm->LastIndex, + jm->EndFile, + jm->EndBlock, + edit_uint64(jm->JobBytes, ed3), edit_int64(jm->JobId, ed1), - edit_int64(jm->MediaId, ed2), - jm->FirstIndex, jm->LastIndex, - jm->StartFile, jm->EndFile, - jm->StartBlock, jm->EndBlock, - count, - edit_uint64(jm->JobBytes, ed3)); + edit_int64(jm->MediaId, ed2)); /* clang-format on */ + bool update_result = false; + bool insert_result = false; Dmsg0(300, cmd); - if (INSERT_DB(jcr, cmd) != 1) { - Mmsg2(errmsg, _("Create JobMedia record %s failed: ERR=%s\n"), cmd, - sql_strerror()); + + if (UPDATE_DB(jcr, cmd) <= 0) { + Mmsg2(errmsg, + _("Update JobMedia record %s failed: ERR=%s\n Trying to insert: \n"), + cmd, sql_strerror()); + + Mmsg(cmd, "SELECT count(*) from JobMedia WHERE JobId=%s", + edit_int64(jm->JobId, ed1)); + count = GetSqlRecordMax(jcr); + if (count < 0) { count = 0; } + count++; + + /* clang-format off */ + Mmsg(cmd, + "INSERT INTO JobMedia (JobId,MediaId,FirstIndex,LastIndex," + "StartFile,EndFile,StartBlock,EndBlock,VolIndex,JobBytes) " + "VALUES (%s,%s,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%s)", + edit_int64(jm->JobId, ed1), + edit_int64(jm->MediaId, ed2), + jm->FirstIndex, jm->LastIndex, + jm->StartFile, jm->EndFile, + jm->StartBlock, jm->EndBlock, + count, + edit_uint64(jm->JobBytes, ed3)); + /* clang-format on */ + + if (INSERT_DB(jcr, cmd) != 1) { + Mmsg2(errmsg, _("Create JobMedia record %s failed: ERR=%s\n"), cmd, + sql_strerror()); + } else { + insert_result = true; + } } else { + update_result = true; + } + + if (update_result || insert_result) { // Worked, now update the Media record with the EndFile and EndBlock Mmsg(cmd, "UPDATE Media SET EndFile=%u, EndBlock=%u WHERE MediaId=%u", jm->EndFile, jm->EndBlock, jm->MediaId); @@ -759,8 +786,6 @@ bool BareosDb::WriteBatchFileRecords(JobControlRecord* jcr) return true; } - if (JobCanceled(jcr)) { goto bail_out; } - Dmsg1(50, "db_create_file_record changes=%u\n", changes); jcr->JobStatus = JS_AttrInserting; @@ -774,8 +799,6 @@ bool BareosDb::WriteBatchFileRecords(JobControlRecord* jcr) goto bail_out; } - if (JobCanceled(jcr)) { goto bail_out; } - if (!jcr->db_batch->SqlQuery(SQL_QUERY::batch_lock_path_query)) { Jmsg1(jcr, M_FATAL, 0, "Lock Path table %s\n", errmsg); goto bail_out; diff --git a/core/src/cats/sql_update.cc b/core/src/cats/sql_update.cc index b924e643d..525d9dadf 100644 --- a/core/src/cats/sql_update.cc +++ b/core/src/cats/sql_update.cc @@ -100,16 +100,26 @@ bool BareosDb::UpdateJobStartRecord(JobControlRecord* jcr, JobDbRecord* jr) DbLocker _{this}; Mmsg(cmd, "UPDATE Job SET JobStatus='%c',Level='%c',StartTime='%s'," - "ClientId=%s,JobTDate=%s,PoolId=%s,FileSetId=%s WHERE JobId=%s", + "ClientId=%s,JobTDate=%s,PoolId=%s,FileSetId=%s,VolSessionId=%lu," + "VolSessionTime=%lu WHERE JobId=%s", (char)(jcr->JobStatus), (char)(jr->JobLevel), dt, edit_int64(jr->ClientId, ed1), edit_uint64(JobTDate, ed2), edit_int64(jr->PoolId, ed3), edit_int64(jr->FileSetId, ed4), - edit_int64(jr->JobId, ed5)); + jcr->VolSessionId, jcr->VolSessionTime, edit_int64(jr->JobId, ed5)); changes = 0; return UPDATE_DB(jcr, cmd) > 0; } +bool BareosDb::UpdateRunningJobRecord(JobControlRecord* jcr) +{ + DbLocker _{this}; + Mmsg(cmd, "UPDATE Job SET JobBytes=%llu,JobFiles=%lu WHERE JobId=%lu", + jcr->JobBytes, jcr->JobFiles, jcr->JobId); + + return UPDATE_DB(jcr, cmd) > 0; +} + // Update Long term statistics with all jobs that were run before age seconds int BareosDb::UpdateStats(JobControlRecord* jcr, utime_t age) { @@ -161,6 +171,7 @@ bool BareosDb::UpdateJobEndRecord(JobControlRecord* jcr, JobDbRecord* jr) JobTDate = ttime; DbLocker _{this}; + Mmsg( cmd, "UPDATE Job SET JobStatus='%c',Level='%c',EndTime='%s'," diff --git a/core/src/dird/catreq.cc b/core/src/dird/catreq.cc index abe418ddb..f2e712a5d 100644 --- a/core/src/dird/catreq.cc +++ b/core/src/dird/catreq.cc @@ -3,7 +3,7 @@ Copyright (C) 2001-2012 Free Software Foundation Europe e.V. Copyright (C) 2011-2016 Planets Communications B.V. - Copyright (C) 2013-2020 Bareos GmbH & Co. KG + Copyright (C) 2013-2022 Bareos GmbH & Co. KG This program is Free Software; you can redistribute it and/or modify it under the terms of version three of the GNU Affero General Public @@ -66,6 +66,11 @@ static char Create_job_media[] " FirstIndex=%u LastIndex=%u StartFile=%u EndFile=%u " " StartBlock=%u EndBlock=%u Copy=%d Strip=%d MediaId=%lld\n"; +static char Update_filelist[] = "Catreq Job=%127s UpdateFileList\n"; + +static char Update_jobrecord[] + = "Catreq Job=%127s UpdateJobRecord JobFiles=%lu JobBytes=%llu\n"; + // Responses sent to Storage daemon static char OK_media[] = "1000 OK VolName=%s VolJobs=%u VolFiles=%u" @@ -126,6 +131,9 @@ void CatalogRequest(JobControlRecord* jcr, BareosSocket* bs) return; } + uint32_t update_jobfiles = 0; + uint64_t update_jobbytes = 0; + // Find next appendable medium for SD unwanted_volumes.check_size(bs->message_length); if (sscanf(bs->msg, Find_media, &Job, &index, &pool_name, &mr.MediaType, @@ -340,6 +348,28 @@ void CatalogRequest(JobControlRecord* jcr, BareosSocket* bs) Dmsg0(400, "JobMedia record created\n"); bs->fsend(OK_create); } + } else if (sscanf(bs->msg, Update_filelist, &Job) == 1) { + Dmsg0(0, "Updating filelist\n"); + + if (!jcr->db_batch->WriteBatchFileRecords(jcr)) { + Jmsg(jcr, M_FATAL, 0, _("Catalog error updating File table. %s\n"), + jcr->db_batch->strerror()); + bs->fsend(_("1992 Update File table error\n")); + } + + } else if (sscanf(bs->msg, Update_jobrecord, &Job, &update_jobfiles, + &update_jobbytes) + == 3) { + Dmsg0(0, "Updating job record\n"); + + jcr->JobFiles = update_jobfiles; + jcr->JobBytes = update_jobbytes; + + if (!jcr->db->UpdateRunningJobRecord(jcr)) { + Jmsg(jcr, M_FATAL, 0, _("Catalog error updating Job record. %s\n"), + jcr->db->strerror()); + bs->fsend(_("1992 Update job record error\n")); + } } else { omsg = GetMemory(bs->message_length + 1); PmStrcpy(omsg, bs->msg); diff --git a/core/src/stored/append.cc b/core/src/stored/append.cc index fe9e18dd7..e6bc002e5 100644 --- a/core/src/stored/append.cc +++ b/core/src/stored/append.cc @@ -25,19 +25,17 @@ * Append code for Storage daemon */ -#include "include/bareos.h" +#include "stored/append.h" #include "stored/stored.h" #include "stored/acquire.h" -#include "stored/append.h" -#include "stored/device_control_record.h" #include "stored/fd_cmds.h" +#include "stored/stored_globals.h" #include "stored/jcr_private.h" #include "stored/label.h" #include "stored/spool.h" #include "lib/bget_msg.h" #include "lib/edit.h" #include "include/jcr.h" -#include "lib/bsock.h" #include "lib/berrno.h" #include "lib/berrno.h" @@ -52,22 +50,127 @@ static char OK_replicate[] = "3000 OK replicate data\n"; void PossibleIncompleteJob(JobControlRecord* jcr, int32_t last_file_index) {} + +ProcessedFileData::ProcessedFileData(DeviceRecord* record) + : volsessionid_(record->VolSessionId) + , volsessiontime_(record->VolSessionTime) + , fileindex_(record->FileIndex) + , stream_(record->Stream) + , data_len_(record->data_len) + , data_(record->data, record->data + record->data_len) +{ +} + +DeviceRecord ProcessedFileData::GetData() +{ + DeviceRecord devicerecord{}; + devicerecord.VolSessionId = volsessionid_; + devicerecord.VolSessionTime = volsessiontime_; + devicerecord.FileIndex = fileindex_; + devicerecord.Stream = stream_; + devicerecord.data_len = data_len_; + devicerecord.data = data_.data(); + + return devicerecord; +} + +ProcessedFile::ProcessedFile(int32_t fileindex) : fileindex_(fileindex) {} + +void ProcessedFile::SendAttributesToDirector(JobControlRecord* jcr) +{ + for_each(attributes_.begin(), attributes_.end(), + [&jcr](ProcessedFileData& attribute) { + DeviceRecord devicerecord = attribute.GetData(); + SendAttrsToDir(jcr, &devicerecord); + }); +} + +void ProcessedFile::AddAttribute(DeviceRecord* record) +{ + attributes_.emplace_back(ProcessedFileData(record)); +} + +bool IsAttribute(DeviceRecord* record) +{ + return record->maskedStream == STREAM_UNIX_ATTRIBUTES + || record->maskedStream == STREAM_UNIX_ATTRIBUTES_EX + || record->maskedStream == STREAM_RESTORE_OBJECT + || CryptoDigestStreamType(record->maskedStream) != CRYPTO_DIGEST_NONE; +} + +static void UpdateFileList(JobControlRecord* jcr) +{ + Dmsg0(100, _("... update file list\n")); + jcr->impl->dcr->DirAskToUpdateFileList(); +} + +static void UpdateJobmediaRecord(JobControlRecord* jcr) +{ + Dmsg0(100, _("... create job media record\n")); + jcr->impl->dcr->DirCreateJobmediaRecord(false); +} + +static void UpdateJobrecord(JobControlRecord* jcr) +{ + Dmsg2(100, _("... update job record: %llu bytes %lu files\n"), jcr->JobBytes, + jcr->JobFiles); + jcr->impl->dcr->DirAskToUpdateJobRecord(); +} + +void DoBackupCheckpoint(JobControlRecord* jcr) +{ + Jmsg(jcr, M_INFO, 0, + _("Checkpoint: Syncing current backup status to catalog\n")); + UpdateJobrecord(jcr); + UpdateFileList(jcr); + UpdateJobmediaRecord(jcr); + Jmsg(jcr, M_INFO, 0, _("Checkpoint completed\n")); +} + +static time_t DoTimedCheckpoint(JobControlRecord* jcr, + time_t checkpoint_time, + time_t checkpoint_interval) +{ + const time_t now + = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + if (now > checkpoint_time) { + while (checkpoint_time <= now) { checkpoint_time += checkpoint_interval; } + Jmsg(jcr, M_INFO, 0, + _("Doing timed backup checkpoint. Next checkpoint in %d seconds\n"), + checkpoint_interval); + DoBackupCheckpoint(jcr); + } + + return checkpoint_time; +} + +static void SaveFullyProcessedFiles(JobControlRecord* jcr, + std::vector<ProcessedFile>& processed_files) +{ + if (!processed_files.empty()) { + for_each( + processed_files.begin(), processed_files.end(), + [&jcr](ProcessedFile& file) { file.SendAttributesToDirector(jcr); }); + jcr->JobFiles = processed_files.back().GetFileIndex(); + processed_files.clear(); + } +} + // Append Data sent from File daemon bool DoAppendData(JobControlRecord* jcr, BareosSocket* bs, const char* what) { int32_t n, file_index, stream, last_file_index, job_elapsed; bool ok = true; char buf1[100]; - DeviceControlRecord* dcr = jcr->impl->dcr; Device* dev; POOLMEM* rec_data; char ec[50]; - if (!dcr) { + if (!jcr->impl->dcr) { Jmsg0(jcr, M_FATAL, 0, _("DeviceControlRecord is NULL!!!\n")); return false; } - dev = dcr->dev; + dev = jcr->impl->dcr->dev; if (!dev) { Jmsg0(jcr, M_FATAL, 0, _("Device is NULL!!!\n")); return false; @@ -75,16 +178,23 @@ bool DoAppendData(JobControlRecord* jcr, BareosSocket* bs, const char* what) Dmsg1(100, "Start append data. res=%d\n", dev->NumReserved()); - if (!bs->SetBufferSize(dcr->device_resource->max_network_buffer_size, - BNET_SETBUF_WRITE)) { + if (!bs->SetBufferSize( + jcr->impl->dcr->device_resource->max_network_buffer_size, + BNET_SETBUF_WRITE)) { Jmsg0(jcr, M_FATAL, 0, _("Unable to set network buffer size.\n")); - goto bail_out; + jcr->setJobStatus(JS_ErrorTerminated); + return false; } - if (!AcquireDeviceForAppend(dcr)) { goto bail_out; } + if (!AcquireDeviceForAppend(jcr->impl->dcr)) { + jcr->setJobStatus(JS_ErrorTerminated); + return false; + } - if (GeneratePluginEvent(jcr, bSdEventSetupRecordTranslation, dcr) != bRC_OK) { - goto bail_out; + if (GeneratePluginEvent(jcr, bSdEventSetupRecordTranslation, jcr->impl->dcr) + != bRC_OK) { + jcr->setJobStatus(JS_ErrorTerminated); + return false; } jcr->sendJobStatus(JS_Running); @@ -94,11 +204,15 @@ bool DoAppendData(JobControlRecord* jcr, BareosSocket* bs, const char* what) } Dmsg1(50, "Begin append device=%s\n", dev->print_name()); - if (!BeginDataSpool(dcr)) { goto bail_out; } + if (!BeginDataSpool(jcr->impl->dcr)) { + jcr->setJobStatus(JS_ErrorTerminated); + return false; + } if (!BeginAttributeSpool(jcr)) { - DiscardDataSpool(dcr); - goto bail_out; + DiscardDataSpool(jcr->impl->dcr); + jcr->setJobStatus(JS_ErrorTerminated); + return false; } Dmsg0(100, "Just after AcquireDeviceForAppend\n"); @@ -107,7 +221,7 @@ bool DoAppendData(JobControlRecord* jcr, BareosSocket* bs, const char* what) } // Write Begin Session Record - if (!WriteSessionLabel(dcr, SOS_LABEL)) { + if (!WriteSessionLabel(jcr->impl->dcr, SOS_LABEL)) { Jmsg1(jcr, M_FATAL, 0, _("Write session label failed. ERR=%s\n"), dev->bstrerror()); jcr->setJobStatus(JS_ErrorTerminated); @@ -142,8 +256,19 @@ bool DoAppendData(JobControlRecord* jcr, BareosSocket* bs, const char* what) * file. 1. for the Attributes, 2. for the file data if any, * and 3. for the MD5 if any. */ - dcr->VolFirstIndex = dcr->VolLastIndex = 0; + jcr->impl->dcr->VolFirstIndex = jcr->impl->dcr->VolLastIndex = 0; jcr->run_time = time(NULL); /* start counting time for rates */ + + auto now + = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + time_t next_checkpoint_time = now + me->checkpoint_interval; + + std::vector<ProcessedFile> processed_files{}; + int64_t current_volumeid = jcr->impl->dcr->VolMediaId; + + ProcessedFile file_currently_processed; + uint32_t current_block_number = jcr->impl->dcr->block->BlockNumber; + for (last_file_index = 0; ok && !jcr->IsJobCanceled();) { /* * Read Stream header from the daemon. @@ -180,24 +305,28 @@ bool DoAppendData(JobControlRecord* jcr, BareosSocket* bs, const char* what) * An incomplete job can start the file_index at any number. * otherwise, it must start at 1. */ - if (jcr->rerunning && file_index > 0 && last_file_index == 0) { - goto fi_checked; - } - if (file_index > 0 - && (file_index == last_file_index - || file_index == last_file_index + 1)) { - goto fi_checked; + + bool incomplete_job_rerun_fileindex_positive + = jcr->rerunning && file_index > 0 && last_file_index == 0; + bool fileindex_is_sequential = file_index > 0 + && (file_index == last_file_index + || file_index == last_file_index + 1); + + if (!incomplete_job_rerun_fileindex_positive && !fileindex_is_sequential) { + Jmsg3(jcr, M_FATAL, 0, + _("FileIndex=%d from %s not positive or sequential=%d\n"), + file_index, what, last_file_index); + PossibleIncompleteJob(jcr, last_file_index); + ok = false; + break; } - Jmsg3(jcr, M_FATAL, 0, _("FI=%d from %s not positive or sequential=%d\n"), - file_index, what, last_file_index); - PossibleIncompleteJob(jcr, last_file_index); - ok = false; - break; - fi_checked: if (file_index != last_file_index) { - jcr->JobFiles = file_index; last_file_index = file_index; + if (file_currently_processed.GetFileIndex() > 0) { + processed_files.push_back(std::move(file_currently_processed)); + } + file_currently_processed = ProcessedFile{file_index}; } /* @@ -205,35 +334,57 @@ bool DoAppendData(JobControlRecord* jcr, BareosSocket* bs, const char* what) * We save the original data pointer from the record so we can restore * that after the loop ends. */ - rec_data = dcr->rec->data; + rec_data = jcr->impl->dcr->rec->data; while ((n = BgetMsg(bs)) > 0 && !jcr->IsJobCanceled()) { - dcr->rec->VolSessionId = jcr->VolSessionId; - dcr->rec->VolSessionTime = jcr->VolSessionTime; - dcr->rec->FileIndex = file_index; - dcr->rec->Stream = stream; - dcr->rec->maskedStream = stream & STREAMMASK_TYPE; /* strip high bits */ - dcr->rec->data_len = bs->message_length; - dcr->rec->data = bs->msg; /* use message buffer */ + jcr->impl->dcr->rec->VolSessionId = jcr->VolSessionId; + jcr->impl->dcr->rec->VolSessionTime = jcr->VolSessionTime; + jcr->impl->dcr->rec->FileIndex = file_index; + jcr->impl->dcr->rec->Stream = stream; + jcr->impl->dcr->rec->maskedStream + = stream & STREAMMASK_TYPE; /* strip high bits */ + jcr->impl->dcr->rec->data_len = bs->message_length; + jcr->impl->dcr->rec->data = bs->msg; /* use message buffer */ Dmsg4(850, "before writ_rec FI=%d SessId=%d Strm=%s len=%d\n", - dcr->rec->FileIndex, dcr->rec->VolSessionId, - stream_to_ascii(buf1, dcr->rec->Stream, dcr->rec->FileIndex), - dcr->rec->data_len); + jcr->impl->dcr->rec->FileIndex, jcr->impl->dcr->rec->VolSessionId, + stream_to_ascii(buf1, jcr->impl->dcr->rec->Stream, + jcr->impl->dcr->rec->FileIndex), + jcr->impl->dcr->rec->data_len); - ok = dcr->WriteRecord(); + ok = jcr->impl->dcr->WriteRecord(); if (!ok) { Dmsg2(90, "Got WriteBlockToDev error on device %s. %s\n", - dcr->dev->print_name(), dcr->dev->bstrerror()); + jcr->impl->dcr->dev->print_name(), + jcr->impl->dcr->dev->bstrerror()); break; } - SendAttrsToDir(jcr, dcr->rec); + if (current_block_number != jcr->impl->dcr->block->BlockNumber) { + current_block_number = jcr->impl->dcr->block->BlockNumber; + SaveFullyProcessedFiles(jcr, processed_files); + } + + if (IsAttribute(jcr->impl->dcr->rec)) { + file_currently_processed.AddAttribute(jcr->impl->dcr->rec); + } + + if (me->checkpoint_interval) { + if (jcr->impl->dcr->VolMediaId != current_volumeid) { + Jmsg0(jcr, M_INFO, 0, _("Volume changed, doing checkpoint:\n")); + DoBackupCheckpoint(jcr); + current_volumeid = jcr->impl->dcr->VolMediaId; + } else { + next_checkpoint_time = DoTimedCheckpoint(jcr, next_checkpoint_time, + me->checkpoint_interval); + } + } + Dmsg0(650, "Enter bnet_get\n"); } Dmsg2(650, "End read loop with %s. Stat=%d\n", what, n); // Restore the original data pointer. - dcr->rec->data = rec_data; + jcr->impl->dcr->rec->data = rec_data; if (bs->IsError()) { if (!jcr->IsJobCanceled()) { @@ -268,7 +419,7 @@ bool DoAppendData(JobControlRecord* jcr, BareosSocket* bs, const char* what) * if we are at the end of the tape or we got a fatal I/O error. */ if (ok || dev->CanWrite()) { - if (!WriteSessionLabel(dcr, EOS_LABEL)) { + if (!WriteSessionLabel(jcr->impl->dcr, EOS_LABEL)) { // Print only if ok and not cancelled to avoid spurious messages if (ok && !jcr->IsJobCanceled()) { Jmsg1(jcr, M_FATAL, 0, _("Error writing end session label. ERR=%s\n"), @@ -281,7 +432,7 @@ bool DoAppendData(JobControlRecord* jcr, BareosSocket* bs, const char* what) Dmsg0(90, "back from write_end_session_label()\n"); // Flush out final partial block of this session - if (!dcr->WriteBlockToDevice()) { + if (!jcr->impl->dcr->WriteBlockToDevice()) { // Print only if ok and not cancelled to avoid spurious messages if (ok && !jcr->IsJobCanceled()) { Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"), @@ -291,18 +442,22 @@ bool DoAppendData(JobControlRecord* jcr, BareosSocket* bs, const char* what) } jcr->setJobStatus(JS_ErrorTerminated); ok = false; + } else if (ok && !jcr->IsJobCanceled()) { + // Send attributes of the final partial block of the session + processed_files.push_back(std::move(file_currently_processed)); + SaveFullyProcessedFiles(jcr, processed_files); } } if (!ok && !jcr->is_JobStatus(JS_Incomplete)) { - DiscardDataSpool(dcr); + DiscardDataSpool(jcr->impl->dcr); } else { // Note: if commit is OK, the device will remain blocked - CommitDataSpool(dcr); + CommitDataSpool(jcr->impl->dcr); } // Release the device -- and send final Vol info to DIR and unlock it. - ReleaseDevice(dcr); + ReleaseDevice(jcr->impl->dcr); /* * Don't use time_t for job_elapsed as time_t can be 32 or 64 bits, @@ -326,33 +481,23 @@ bool DoAppendData(JobControlRecord* jcr, BareosSocket* bs, const char* what) Dmsg1(100, "return from DoAppendData() ok=%d\n", ok); return ok; - -bail_out: - jcr->setJobStatus(JS_ErrorTerminated); - return false; } // Send attributes and digest to Director for Catalog bool SendAttrsToDir(JobControlRecord* jcr, DeviceRecord* rec) { - if (rec->maskedStream == STREAM_UNIX_ATTRIBUTES - || rec->maskedStream == STREAM_UNIX_ATTRIBUTES_EX - || rec->maskedStream == STREAM_RESTORE_OBJECT - || CryptoDigestStreamType(rec->maskedStream) != CRYPTO_DIGEST_NONE) { - if (!jcr->impl->no_attributes) { - BareosSocket* dir = jcr->dir_bsock; - if (AreAttributesSpooled(jcr)) { dir->SetSpooling(); } - Dmsg0(850, "Send attributes to dir.\n"); - if (!jcr->impl->dcr->DirUpdateFileAttributes(rec)) { - Jmsg(jcr, M_FATAL, 0, _("Error updating file attributes. ERR=%s\n"), - dir->bstrerror()); - dir->ClearSpooling(); - return false; - } + if (!jcr->impl->no_attributes) { + BareosSocket* dir = jcr->dir_bsock; + if (AreAttributesSpooled(jcr)) { dir->SetSpooling(); } + Dmsg0(850, "Send attributes to dir.\n"); + if (!jcr->impl->dcr->DirUpdateFileAttributes(rec)) { + Jmsg(jcr, M_FATAL, 0, _("Error updating file attributes. ERR=%s\n"), + dir->bstrerror()); dir->ClearSpooling(); + return false; } + dir->ClearSpooling(); } return true; } - } /* namespace storagedaemon */ diff --git a/core/src/stored/append.h b/core/src/stored/append.h index adea9c65f..5b5b969b2 100644 --- a/core/src/stored/append.h +++ b/core/src/stored/append.h @@ -1,7 +1,7 @@ /* BAREOS® - Backup Archiving REcovery Open Sourced - Copyright (C) 2018-2018 Bareos GmbH & Co. KG + Copyright (C) 2018-2022 Bareos GmbH & Co. KG This program is Free Software; you can redistribute it and/or modify it under the terms of version three of the GNU Affero General Public @@ -21,11 +21,51 @@ #ifndef BAREOS_STORED_APPEND_H_ #define BAREOS_STORED_APPEND_H_ + +#include "include/bareos.h" +#include "lib/bsock.h" +#include "stored/device_control_record.h" +#include "stored/record.h" + namespace storagedaemon { +class ProcessedFileData { + public: + explicit ProcessedFileData(DeviceRecord* record); + DeviceRecord GetData(); + + private: + uint32_t volsessionid_{0}; + uint32_t volsessiontime_{0}; + int32_t fileindex_{0}; + int32_t stream_{0}; + uint32_t data_len_{0}; + std::string data_{}; +}; + +class ProcessedFile { + public: + ProcessedFile() = default; + explicit ProcessedFile(int32_t fileindex); + + void SendAttributesToDirector(JobControlRecord* jcr); + void AddAttribute(DeviceRecord* record); + int32_t GetFileIndex() { return fileindex_; } + const std::vector<ProcessedFileData>& GetAttributes() const + { + return attributes_; + } + + private: + int32_t fileindex_{-1}; + std::vector<ProcessedFileData> attributes_; +}; + bool DoAppendData(JobControlRecord* jcr, BareosSocket* bs, const char* what); +bool IsAttribute(DeviceRecord* record); bool SendAttrsToDir(JobControlRecord* jcr, DeviceRecord* rec); +void DoBackupCheckpoint(JobControlRecord* jcr); } // namespace storagedaemon #endif // BAREOS_STORED_APPEND_H_ diff --git a/core/src/stored/askdir.cc b/core/src/stored/askdir.cc index 045e0ca19..4e6ebc911 100644 --- a/core/src/stored/askdir.cc +++ b/core/src/stored/askdir.cc @@ -62,8 +62,15 @@ static char Create_job_media[] = "CatReq Job=%s CreateJobMedia" " FirstIndex=%u LastIndex=%u StartFile=%u EndFile=%u" " StartBlock=%u EndBlock=%u Copy=%d Strip=%d MediaId=%s\n"; + +static char Update_filelist[] = "Catreq Job=%s UpdateFileList\n"; + +static char Update_jobrecord[] + = "Catreq Job=%s UpdateJobRecord JobFiles=%lu JobBytes=%llu\n"; + static char FileAttributes[] = "UpdCat Job=%s FileAttributes "; + /* Responses received from the Director */ static char OK_media[] = "1000 OK VolName=%127s VolJobs=%u VolFiles=%lu" @@ -618,6 +625,19 @@ get_out: return true; } +bool StorageDaemonDeviceControlRecord::DirAskToUpdateFileList() +{ + BareosSocket* dir = jcr->dir_bsock; + return dir->fsend(Update_filelist, jcr->Job); +} + +bool StorageDaemonDeviceControlRecord::DirAskToUpdateJobRecord() +{ + BareosSocket* dir = jcr->dir_bsock; + return dir->fsend(Update_jobrecord, jcr->Job, jcr->JobFiles, jcr->JobBytes); +} + + // Dummy methods for everything but SD and BTAPE. bool DeviceControlRecord::DirAskSysopToMountVolume(int /*mode*/) { diff --git a/core/src/stored/block.cc b/core/src/stored/block.cc index bddbef5ec..322fdf4f1 100644 --- a/core/src/stored/block.cc +++ b/core/src/stored/block.cc @@ -3,7 +3,7 @@ Copyright (C) 2001-2012 Free Software Foundation Europe e.V. Copyright (C) 2011-2012 Planets Communications B.V. - Copyright (C) 2013-2021 Bareos GmbH & Co. KG + Copyright (C) 2013-2022 Bareos GmbH & Co. KG This program is Free Software; you can redistribute it and/or modify it under the terms of version three of the GNU Affero General Public @@ -843,7 +843,6 @@ bool DeviceControlRecord::WriteBlockToDev() return true; } - /** * Write a block to the device, with locking and unlocking * diff --git a/core/src/stored/device_control_record.h b/core/src/stored/device_control_record.h index 085d1c3f7..2c670904d 100644 --- a/core/src/stored/device_control_record.h +++ b/core/src/stored/device_control_record.h @@ -3,7 +3,7 @@ Copyright (C) 2000-2012 Free Software Foundation Europe e.V. Copyright (C) 2011-2012 Planets Communications B.V. - Copyright (C) 2013-2021 Bareos GmbH & Co. KG + Copyright (C) 2013-2022 Bareos GmbH & Co. KG This program is Free Software; you can redistribute it and/or modify it under the terms of version three of the GNU Affero General Public @@ -153,6 +153,8 @@ class DeviceControlRecord { virtual bool DirAskSysopToMountVolume(int mode); virtual bool DirAskSysopToCreateAppendableVolume() { return true; } virtual bool DirGetVolumeInfo(enum get_vol_info_rw writing); + virtual bool DirAskToUpdateFileList() { return true;} + virtual bool DirAskToUpdateJobRecord() { return true;} // Methods in lock.c void dblock(int why); diff --git a/core/src/stored/dir_cmd.cc b/core/src/stored/dir_cmd.cc index 625ce9954..a15609d0e 100644 --- a/core/src/stored/dir_cmd.cc +++ b/core/src/stored/dir_cmd.cc @@ -40,6 +40,7 @@ */ #include "include/bareos.h" +#include "stored/append.h" #include "stored/stored.h" #include "stored/acquire.h" #include "stored/authenticate.h" @@ -1720,7 +1721,8 @@ static bool RunCmd(JobControlRecord* jcr) { Dmsg1(200, "Run_cmd: %s\n", jcr->dir_bsock->msg); - // If we do not need the FD, we are doing a migrate, copy, or virtual backup. + // If we do not need the FD, we are doing a migrate, copy, or virtual + // backup. if (jcr->NoClientUsed()) { return DoMacRun(jcr); } else { diff --git a/core/src/stored/mac.cc b/core/src/stored/mac.cc index 543139d37..38b952eff 100644 --- a/core/src/stored/mac.cc +++ b/core/src/stored/mac.cc @@ -255,7 +255,9 @@ static bool CloneRecordInternally(DeviceControlRecord* dcr, DeviceRecord* rec) jcr->impl->dcr->after_rec->FileIndex), jcr->impl->dcr->after_rec->data_len); - SendAttrsToDir(jcr, jcr->impl->dcr->after_rec); + if (IsAttribute(jcr->impl->dcr->after_rec)) { + SendAttrsToDir(jcr, jcr->impl->dcr->after_rec); + } retval = true; diff --git a/core/src/stored/record.cc b/core/src/stored/record.cc index 0a4440d5f..ed23db09b 100644 --- a/core/src/stored/record.cc +++ b/core/src/stored/record.cc @@ -2,7 +2,7 @@ BAREOS® - Backup Archiving REcovery Open Sourced Copyright (C) 2001-2012 Free Software Foundation Europe e.V. - Copyright (C) 2016-2020 Bareos GmbH & Co. KG + Copyright (C) 2016-2022 Bareos GmbH & Co. KG This program is Free Software; you can redistribute it and/or modify it under the terms of version three of the GNU Affero General Public @@ -709,7 +709,6 @@ bail_out: bool WriteRecordToBlock(DeviceControlRecord* dcr, DeviceRecord* rec) { ssize_t n; - bool retval = false; char buf1[100], buf2[100]; DeviceBlock* block = dcr->block; @@ -745,7 +744,7 @@ bool WriteRecordToBlock(DeviceControlRecord* dcr, DeviceRecord* rec) * the header did not fit into the block, so flush the current * block and come back to st_header and try again on the next block. */ - goto bail_out; + return false; } if (BlockWriteNavail(block) == 0) { @@ -755,7 +754,7 @@ bool WriteRecordToBlock(DeviceControlRecord* dcr, DeviceRecord* rec) * continuation header. */ rec->state = st_header_cont; - goto bail_out; + return false; } /* @@ -789,7 +788,7 @@ bool WriteRecordToBlock(DeviceControlRecord* dcr, DeviceRecord* rec) * so flush the block and start the next block with * data bytes */ - goto bail_out; /* Partial transfer */ + return false; /* Partial transfer */ } continue; @@ -820,26 +819,23 @@ bool WriteRecordToBlock(DeviceControlRecord* dcr, DeviceRecord* rec) * continuation header */ rec->state = st_header_cont; - goto bail_out; + return false; } } rec->remainder = 0; /* did whole transfer */ rec->state = st_none; - retval = true; - goto bail_out; + return true; default: Emsg1(M_ABORT, 0, _("Something went wrong. Unknown state %d.\n"), rec->state); rec->state = st_none; - retval = true; - goto bail_out; + return true; } } -bail_out: - return retval; + return false; } /** diff --git a/core/src/stored/sd_device_control_record.h b/core/src/stored/sd_device_control_record.h index b41f60cb8..f220f3823 100644 --- a/core/src/stored/sd_device_control_record.h +++ b/core/src/stored/sd_device_control_record.h @@ -3,7 +3,7 @@ Copyright (C) 2000-2012 Free Software Foundation Europe e.V. Copyright (C) 2011-2012 Planets Communications B.V. - Copyright (C) 2013-2021 Bareos GmbH & Co. KG + Copyright (C) 2013-2022 Bareos GmbH & Co. KG This program is Free Software; you can redistribute it and/or modify it under the terms of version three of the GNU Affero General Public @@ -37,6 +37,8 @@ class StorageDaemonDeviceControlRecord : public DeviceControlRecord { bool DirAskSysopToMountVolume(int mode) override; bool DirAskSysopToCreateAppendableVolume() override; bool DirGetVolumeInfo(enum get_vol_info_rw writing) override; + bool DirAskToUpdateFileList() override; + bool DirAskToUpdateJobRecord() override; DeviceControlRecord* get_new_spooling_dcr() override; }; diff --git a/core/src/stored/stored_conf.cc b/core/src/stored/stored_conf.cc index 0dd6338f0..bbe5e4647 100644 --- a/core/src/stored/stored_conf.cc +++ b/core/src/stored/stored_conf.cc @@ -92,6 +92,7 @@ static ResourceItem store_items[] = { {"SdConnectTimeout", CFG_TYPE_TIME, ITEM(res_store, SDConnectTimeout), 0, CFG_ITEM_DEFAULT, "1800" /* 30 minutes */, NULL, NULL}, {"FdConnectTimeout", CFG_TYPE_TIME, ITEM(res_store, FDConnectTimeout), 0, CFG_ITEM_DEFAULT, "1800" /* 30 minutes */, NULL, NULL}, {"HeartbeatInterval", CFG_TYPE_TIME, ITEM(res_store, heartbeat_interval), 0, CFG_ITEM_DEFAULT, "0", NULL, NULL}, + {"CheckpointInterval", CFG_TYPE_TIME, ITEM(res_store, checkpoint_interval), 0, CFG_ITEM_DEFAULT, "60", NULL, NULL}, {"MaximumNetworkBufferSize", CFG_TYPE_PINT32, ITEM(res_store, max_network_buffer_size), 0, 0, NULL, NULL, NULL}, {"ClientConnectWait", CFG_TYPE_TIME, ITEM(res_store, client_wait), 0, CFG_ITEM_DEFAULT, "1800" /* 30 minutes */, NULL, NULL}, {"VerId", CFG_TYPE_STR, ITEM(res_store, verid), 0, 0, NULL, NULL, NULL}, diff --git a/core/src/stored/stored_conf.h b/core/src/stored/stored_conf.h index 925b752f3..3b60a8c0e 100644 --- a/core/src/stored/stored_conf.h +++ b/core/src/stored/stored_conf.h @@ -116,6 +116,7 @@ class StorageResource utime_t SDConnectTimeout = {0}; /**< Timeout in seconds */ utime_t FDConnectTimeout = {0}; /**< Timeout in seconds */ utime_t heartbeat_interval = {0}; /**< Interval to send hb to FD */ + utime_t checkpoint_interval = {0}; /**< Interval to save */ utime_t client_wait = {0}; /**< Time to wait for FD to connect */ uint32_t max_network_buffer_size = 0; /**< Max network buf size */ bool autoxflateonreplication diff --git a/core/src/tests/CMakeLists.txt b/core/src/tests/CMakeLists.txt index 381cfba01..3c067858d 100644 --- a/core/src/tests/CMakeLists.txt +++ b/core/src/tests/CMakeLists.txt @@ -150,6 +150,12 @@ if(NOT client-only) LINK_LIBRARIES bareos dird_objects bareosfind bareossql testing_common $<$<BOOL:HAVE_PAM>:${PAM_LIBRARIES}> GTest::gtest_main ) + + bareos_add_test( + append_test LINK_LIBRARIES bareos stored_objects bareossd bareosfind + GTest::gtest_main + ) + bareos_add_test( berrno_test LINK_LIBRARIES bareos dird_objects bareosfind bareossql diff --git a/core/src/tests/append_test.cc b/core/src/tests/append_test.cc new file mode 100644 index 000000000..cc5879773 --- /dev/null +++ b/core/src/tests/append_test.cc @@ -0,0 +1,58 @@ +/* + BAREOS® - Backup Archiving REcovery Open Sourced + + Copyright (C) 2022-2022 Bareos GmbH & Co. KG + + This program is Free Software; you can redistribute it and/or + modify it under the terms of version three of the GNU Affero General Public + License as published by the Free Software Foundation and included + in the file LICENSE. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ +#if defined(HAVE_MINGW) +# include "include/bareos.h" +#endif + +#include "gtest/gtest.h" + +#include "stored/append.h" + +TEST(AppendProcessedFileTest, ProcessedFileIsEmptyOnInitialization) +{ + storagedaemon::ProcessedFile file{20}; + EXPECT_EQ(file.GetFileIndex(), 20); + EXPECT_TRUE(file.GetAttributes().empty()); +} + +TEST(AppendProcessedFileTest, AddDeviceRecordCopiesDataContentNotPointer) +{ + POOLMEM* test_msg = GetPoolMemory(PM_MESSAGE); + PmStrcpy(test_msg, "data\0more data"); + + storagedaemon::DeviceRecord dr; + dr.data_len = 14; + dr.data = test_msg; + + int32_t arbitrary_index{1234}; + storagedaemon::ProcessedFile file{arbitrary_index}; + file.AddAttribute(&dr); + + EXPECT_FALSE(file.GetAttributes().empty()); + + storagedaemon::ProcessedFileData processedfiledata + = file.GetAttributes().front(); + + EXPECT_NE(processedfiledata.GetData().data, dr.data); + EXPECT_EQ(memcmp(processedfiledata.GetData().data, dr.data, dr.data_len), 0); + + FreePoolMemory(test_msg); +} diff --git a/docs/manuals/source/include/autogenerated/bareos-sd-config-schema.json b/docs/manuals/source/include/autogenerated/bareos-sd-config-schema.json index 951532417..c09cb1191 100644 --- a/docs/manuals/source/include/autogenerated/bareos-sd-config-schema.json +++ b/docs/manuals/source/include/autogenerated/bareos-sd-config-schema.json @@ -266,6 +266,12 @@ "default_value": "0", "equals": true }, + "CheckpointInterval": { + "datatype": "TIME", + "code": 0, + "default_value": "60", + "equals": true + }, "MaximumNetworkBufferSize": { "datatype": "PINT32", "code": 0, diff --git a/docs/manuals/source/manually_added_config_directive_descriptions/sd-storage-CheckpointInterval.rst.inc b/docs/manuals/source/manually_added_config_directive_descriptions/sd-storage-CheckpointInterval.rst.inc new file mode 100644 index 000000000..d5ee828d9 --- /dev/null +++ b/docs/manuals/source/manually_added_config_directive_descriptions/sd-storage-CheckpointInterval.rst.inc @@ -0,0 +1 @@ +:index:`\ <single: checkpoint interval>`\ This is the interval at which Backup checkpoints are executed. When a checkpoint is executed, the files that have been successfully stored into the media at that point in time will be updated in the catalog database. diff --git a/systemtests/environment.in b/systemtests/environment.in index d8999433c..35412151d 100644 --- a/systemtests/environment.in +++ b/systemtests/environment.in @@ -18,6 +18,7 @@ export config_directory_dir_additional_test_config=@config_directory_dir_additio working=${current_test_directory}/working working_dir=${working} +messagesfile=${working_dir}/bareos-dir.conmsg tmp=${current_test_directory}/tmp export BackupDirectory="${tmp}/data" systemtests_s3_use_https=@systemtests_s3_use_https@ diff --git a/systemtests/scripts/functions b/systemtests/scripts/functions index 5e04144ea..a30475e5b 100644 --- a/systemtests/scripts/functions +++ b/systemtests/scripts/functions @@ -1038,7 +1038,7 @@ if [ ! -f ${target_file} ]; then fi if ! grep -q "${expected_result}" "${target_file}"; then - echo "Expected line \"${expected_result}\" was not found in log file \"${target_file}\"." >&2 + echo "Fail: Expected line \"${expected_result}\" was not found in log file \"${target_file}\"." >&2 estat=1 if [ "${error_message}" != "" ]; then echo "-->${error_message}" >&2 diff --git a/systemtests/tests/CMakeLists.txt b/systemtests/tests/CMakeLists.txt index c974f74c9..f33edde3d 100644 --- a/systemtests/tests/CMakeLists.txt +++ b/systemtests/tests/CMakeLists.txt @@ -27,6 +27,7 @@ add_subdirectory(bconsole-pam) add_subdirectory(block-size) add_subdirectory(bscan-bextract-bls-bcopy) add_subdirectory(catalog) +add_subdirectory(checkpoints) add_subdirectory(chflags) add_subdirectory(client-initiated) add_subdirectory(commandline-options) @@ -49,6 +50,7 @@ add_subdirectory(messages) add_subdirectory(multiplied-device) add_subdirectory(ndmp) add_subdirectory(notls) +add_subdirectory(parallel-jobs) add_subdirectory(passive) add_subdirectory(pruning) add_subdirectory(py2plug-dir) @@ -73,6 +75,7 @@ add_subdirectory(scheduler-backup) add_subdirectory(sparse-file) add_subdirectory(spool) add_subdirectory(testfind) +add_subdirectory(stresstest) add_subdirectory(truncate-command) add_subdirectory(upgrade-database) add_subdirectory(virtualfull) diff --git a/systemtests/tests/checkpoints/CMakeLists.txt b/systemtests/tests/checkpoints/CMakeLists.txt new file mode 100644 index 000000000..6cd046c40 --- /dev/null +++ b/systemtests/tests/checkpoints/CMakeLists.txt @@ -0,0 +1,30 @@ +# BAREOS® - Backup Archiving REcovery Open Sourced +# +# Copyright (C) 2022-2022 Bareos GmbH & Co. KG +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of version three of the GNU Affero General Public +# License as published by the Free Software Foundation and included +# in the file LICENSE. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +get_filename_component(BASENAME ${CMAKE_CURRENT_BINARY_DIR} NAME) +create_systemtest(${SYSTEMTEST_PREFIX} ${BASENAME}) + +set_tests_properties( + "${SYSTEMTEST_PREFIX}${BASENAME}:checkpoints-on-stop" PROPERTIES RUN_SERIAL + TRUE +) +set_tests_properties( + "${SYSTEMTEST_PREFIX}${BASENAME}:checkpoints-on-kill" PROPERTIES RUN_SERIAL + TRUE +) diff --git a/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/catalog/MyCatalog.conf.in b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/catalog/MyCatalog.conf.in new file mode 100644 index 000000000..3c3385945 --- /dev/null +++ b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/catalog/MyCatalog.conf.in @@ -0,0 +1,6 @@ +Catalog { + Name = MyCatalog + dbname = "@db_name@" + dbuser = "@db_user@" + dbpassword = "@db_password@" +} diff --git a/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/client/bareos-fd.conf.in b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/client/bareos-fd.conf.in new file mode 100644 index 000000000..59b617009 --- /dev/null +++ b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/client/bareos-fd.conf.in @@ -0,0 +1,7 @@ +Client { + Name = bareos-fd + Description = "Client resource of the Director itself." + Address = @hostname@ + Password = "@fd_password@" # password for FileDaemon + FD PORT = @fd_port@ +} diff --git a/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/director/bareos-dir.conf.in b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/director/bareos-dir.conf.in new file mode 100644 index 000000000..266d120dd --- /dev/null +++ b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/director/bareos-dir.conf.in @@ -0,0 +1,26 @@ +Director { # define myself + Name = bareos-dir + QueryFile = "@scriptdir@/query.sql" + Maximum Concurrent Jobs = 10 + Password = "@dir_password@" # Console password + Messages = Daemon + Auditing = yes + + # Enable the Heartbeat if you experience connection losses + # (eg. because of your router or firewall configuration). + # Additionally the Heartbeat can be enabled in bareos-sd and bareos-fd. + # + # Heartbeat Interval = 1 min + + # remove comment in next line to load dynamic backends from specified directory + Backend Directory = @backenddir@ + + # remove comment from "Plugin Directory" to load plugins from specified directory. + # if "Plugin Names" is defined, only the specified plugins will be loaded, + # otherwise all director plugins (*-dir.so) from the "Plugin Directory". + # + # Plugin Directory = "@python_plugin_module_src_dir@" + # Plugin Names = "" + Working Directory = "@working_dir@" + DirPort = @dir_port@ +} diff --git a/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/fileset/Catalog.conf.in b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/fileset/Catalog.conf.in new file mode 100644 index 000000000..c7cdc433f --- /dev/null +++ b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/fileset/Catalog.conf.in @@ -0,0 +1,11 @@ +FileSet { + Name = "Catalog" + Description = "Backup the catalog dump and Bareos configuration files." + Include { + Options { + signature = MD5 + } + File = "@working_dir@/@db_name@.sql" # database dump + File = "@confdir@" # configuration + } +} diff --git a/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/fileset/SelfTest.conf.in b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/fileset/SelfTest.conf.in new file mode 100644 index 000000000..be175b9a9 --- /dev/null +++ b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/fileset/SelfTest.conf.in @@ -0,0 +1,20 @@ +FileSet { + Name = "SelfTest" + Description = "fileset just to backup some files for selftest" + Include { + Options { + Signature = MD5 # calculate md5 checksum per file + fstype = ext2 + fstype = ext3 + fstype = ext4 + fstype = overlay + fstype = jfs + fstype = ufs + fstype = xfs + fstype = zfs + fstype = btrfs + } + #File = "@sbindir@" + File=<@tmpdir@/file-list + } +} diff --git a/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/job/BackupCatalog.conf.in b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/job/BackupCatalog.conf.in new file mode 100644 index 000000000..1da2a7af6 --- /dev/null +++ b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/job/BackupCatalog.conf.in @@ -0,0 +1,20 @@ +Job { + Name = "BackupCatalog" + Description = "Backup the catalog database (after the nightly save)" + JobDefs = "DefaultJob" + Level = Full + FileSet="Catalog" + + # This creates an ASCII copy of the catalog + # Arguments to make_catalog_backup.pl are: + # make_catalog_backup.pl <catalog-name> + RunBeforeJob = "@scriptdir@/make_catalog_backup.pl MyCatalog" + + # This deletes the copy of the catalog + RunAfterJob = "@scriptdir@/delete_catalog_backup" + + # This sends the bootstrap via mail for disaster recovery. + # Should be sent to another system, please change recipient accordingly + Write Bootstrap = "|@bindir@/bsmtp -h @smtp_host@ -f \"\(Bareos\) \" -s \"Bootstrap for Job %j\" @job_email@" # (#01) + Priority = 11 # run after main backup +} diff --git a/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/job/RestoreFiles.conf.in b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/job/RestoreFiles.conf.in new file mode 100644 index 000000000..89256864d --- /dev/null +++ b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/job/RestoreFiles.conf.in @@ -0,0 +1,11 @@ +Job { + Name = "RestoreFiles" + Description = "Standard Restore template. Only one such job is needed for all standard Jobs/Clients/Storage ..." + Type = Restore + Client = bareos-fd + FileSet = SelfTest + Storage = File + Pool = Incremental + Messages = Standard + Where = @tmp@/bareos-restores +} diff --git a/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/job/backup-bareos-fd.conf b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/job/backup-bareos-fd.conf new file mode 100644 index 000000000..ca1891f96 --- /dev/null +++ b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/job/backup-bareos-fd.conf @@ -0,0 +1,5 @@ +Job { + Name = "backup-bareos-fd" + JobDefs = "DefaultJob" + Client = "bareos-fd" +} diff --git a/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/job/slow-backup-bareos-fd.conf b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/job/slow-backup-bareos-fd.conf new file mode 100644 index 000000000..b9f416f53 --- /dev/null +++ b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/job/slow-backup-bareos-fd.conf @@ -0,0 +1,12 @@ +Job { + Name = "slow-backup-bareos-fd" + Type = Backup + Level = Full + Client = bareos-fd + FileSet = "SelfTest" + Storage = File + Messages = Standard + Pool = SmallFull + Full Backup Pool = SmallFull + Maximum Bandwidth = 10K +} diff --git a/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/jobdefs/DefaultJob.conf.in b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/jobdefs/DefaultJob.conf.in new file mode 100644 index 000000000..563126477 --- /dev/null +++ b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/jobdefs/DefaultJob.conf.in @@ -0,0 +1,15 @@ +JobDefs { + Name = "DefaultJob" + Type = Backup + Level = Incremental + Client = bareos-fd + FileSet = "SelfTest" + Storage = File + Messages = Standard + Pool = Incremental + Priority = 10 + Write Bootstrap = "@working_dir@/%c.bsr" + Full Backup Pool = Full # write Full Backups into "Full" Pool + Differential Backup Pool = Differential # write Diff Backups into "Differential" Pool + Incremental Backup Pool = Incremental # write Incr Backups into "Incremental" Pool +} diff --git a/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/messages/Daemon.conf.in b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/messages/Daemon.conf.in new file mode 100644 index 000000000..cf6a8cfa1 --- /dev/null +++ b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/messages/Daemon.conf.in @@ -0,0 +1,7 @@ +Messages { + Name = Daemon + Description = "Message delivery for daemon messages (no job)." + console = all, !skipped, !saved, !audit + append = "@logdir@/bareos.log" = all, !skipped, !audit + append = "@logdir@/bareos-audit.log" = audit +} diff --git a/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/messages/Standard.conf.in b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/messages/Standard.conf.in new file mode 100644 index 000000000..b3556ba8c --- /dev/null +++ b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/messages/Standard.conf.in @@ -0,0 +1,7 @@ +Messages { + Name = Standard + Description = "Reasonable message delivery -- send most everything to email address and to the console." + console = all, !skipped, !saved, !audit + append = "@logdir@/bareos.log" = all, !skipped, !saved, !audit + catalog = all, !skipped, !saved, !audit +} diff --git a/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/pool/Differential.conf b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/pool/Differential.conf new file mode 100644 index 000000000..25ce24821 --- /dev/null +++ b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/pool/Differential.conf @@ -0,0 +1,10 @@ +Pool { + Name = Differential + Pool Type = Backup + Recycle = yes # Bareos can automatically recycle Volumes + AutoPrune = yes # Prune expired volumes + Volume Retention = 90 days # How long should the Differential Backups be kept? (#09) + Maximum Volume Bytes = 10G # Limit Volume size to something reasonable + Maximum Volumes = 100 # Limit number of Volumes in Pool + Label Format = "Differential-" # Volumes will be labeled "Differential-<volume-id>" +} diff --git a/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/pool/Full.conf b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/pool/Full.conf new file mode 100644 index 000000000..867fc66b4 --- /dev/null +++ b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/pool/Full.conf @@ -0,0 +1,10 @@ +Pool { + Name = Full + Pool Type = Backup + Recycle = yes # Bareos can automatically recycle Volumes + AutoPrune = yes # Prune expired volumes + Volume Retention = 365 days # How long should the Full Backups be kept? (#06) + Maximum Volume Bytes = 50G # Limit Volume size to something reasonable + Maximum Volumes = 100 # Limit number of Volumes in Pool + Label Format = "Full-" # Volumes will be labeled "Full-<volume-id>" +} diff --git a/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/pool/FullSmallvolumes.conf b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/pool/FullSmallvolumes.conf new file mode 100644 index 000000000..aa8d7b5eb --- /dev/null +++ b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/pool/FullSmallvolumes.conf @@ -0,0 +1,11 @@ +Pool { + Name = SmallFull + Pool Type = Backup + Recycle = yes + AutoPrune = yes + Volume Retention = 365 days + Maximum Volume Bytes = 32k + Maximum Volumes = 100 + Label Format = "SmallFull-" + Maximum Block Size = 16K +} diff --git a/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/pool/Incremental.conf b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/pool/Incremental.conf new file mode 100644 index 000000000..f4dbbab66 --- /dev/null +++ b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/pool/Incremental.conf @@ -0,0 +1,10 @@ +Pool { + Name = Incremental + Pool Type = Backup + Recycle = yes # Bareos can automatically recycle Volumes + AutoPrune = yes # Prune expired volumes + Volume Retention = 30 days # How long should the Incremental Backups be kept? (#12) + Maximum Volume Bytes = 1G # Limit Volume size to something reasonable + Maximum Volumes = 100 # Limit number of Volumes in Pool + Label Format = "Incremental-" # Volumes will be labeled "Incremental-<volume-id>" +} diff --git a/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/pool/Scratch.conf b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/pool/Scratch.conf new file mode 100644 index 000000000..3a489b198 --- /dev/null +++ b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/pool/Scratch.conf @@ -0,0 +1,4 @@ +Pool { + Name = Scratch + Pool Type = Scratch +} diff --git a/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/profile/operator.conf b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/profile/operator.conf new file mode 100644 index 000000000..6edd0166d --- /dev/null +++ b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/profile/operator.conf @@ -0,0 +1,18 @@ +Profile { + Name = operator + Description = "Profile allowing normal Bareos operations." + + Command ACL = !.bvfs_clear_cache, !.exit, !.sql + Command ACL = !configure, !create, !delete, !purge, !prune, !sqlquery, !umount, !unmount + Command ACL = *all* + + Catalog ACL = *all* + Client ACL = *all* + FileSet ACL = *all* + Job ACL = *all* + Plugin Options ACL = *all* + Pool ACL = *all* + Schedule ACL = *all* + Storage ACL = *all* + Where ACL = *all* +} diff --git a/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/storage/File.conf.in b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/storage/File.conf.in new file mode 100644 index 000000000..a2622f719 --- /dev/null +++ b/systemtests/tests/checkpoints/etc/bareos/bareos-dir.d/storage/File.conf.in @@ -0,0 +1,8 @@ +Storage { + Name = File + Address = @hostname@ + Password = "@sd_password@" + Device = FileStorage + Media Type = File + SD Port = @sd_port@ +} diff --git a/systemtests/tests/checkpoints/etc/bareos/bareos-fd.d/client/myself.conf.in b/systemtests/tests/checkpoints/etc/bareos/bareos-fd.d/client/myself.conf.in new file mode 100644 index 000000000..6439fe84d --- /dev/null +++ b/systemtests/tests/checkpoints/etc/bareos/bareos-fd.d/client/myself.conf.in @@ -0,0 +1,19 @@ +Client { + Name = @basename@-fd + Maximum Concurrent Jobs = 20 + + # remove comment from "Plugin Directory" to load plugins from specified directory. + # if "Plugin Names" is defined, only the specified plugins will be loaded, + # otherwise all filedaemon plugins (*-fd.so) from the "Plugin Directory". + # + # Plugin Directory = "@python_plugin_module_src_fd@" + # Plugin Names = "" + + # if compatible is set to yes, we are compatible with bacula + # if set to no, new bareos features are enabled which is the default + # compatible = yes + + Working Directory = "@working_dir@" + FD Port = @fd_port@ + +} diff --git a/systemtests/tests/checkpoints/etc/bareos/bareos-fd.d/director/bareos-dir.conf.in b/systemtests/tests/checkpoints/etc/bareos/bareos-fd.d/director/bareos-dir.conf.in new file mode 100644 index 000000000..c8dc7085a --- /dev/null +++ b/systemtests/tests/checkpoints/etc/bareos/bareos-fd.d/director/bareos-dir.conf.in @@ -0,0 +1,5 @@ +Director { + Name = bareos-dir + Password = "@fd_password@" + Description = "Allow the configured Director to access this file daemon." +} diff --git a/systemtests/tests/checkpoints/etc/bareos/bareos-fd.d/messages/Standard.conf b/systemtests/tests/checkpoints/etc/bareos/bareos-fd.d/messages/Standard.conf new file mode 100644 index 000000000..97788e005 --- /dev/null +++ b/systemtests/tests/checkpoints/etc/bareos/bareos-fd.d/messages/Standard.conf @@ -0,0 +1,5 @@ +Messages { + Name = Standard + Director = bareos-dir = all, !skipped, !restored + Description = "Send relevant messages to the Director." +} diff --git a/systemtests/tests/checkpoints/etc/bareos/bareos-sd.d/device/FileStorage.conf b/systemtests/tests/checkpoints/etc/bareos/bareos-sd.d/device/FileStorage.conf new file mode 100644 index 000000000..11a639bc6 --- /dev/null +++ b/systemtests/tests/checkpoints/etc/bareos/bareos-sd.d/device/FileStorage.conf @@ -0,0 +1,11 @@ +Device { + Name = FileStorage + Media Type = File + Archive Device = storage + LabelMedia = yes; # lets Bareos label unlabeled media + Random Access = yes; + AutomaticMount = yes; # when device opened, read it + RemovableMedia = no; + AlwaysOpen = no; + Description = "File device. A connecting Director must have the same Name and MediaType." +} diff --git a/systemtests/tests/checkpoints/etc/bareos/bareos-sd.d/director/bareos-dir.conf.in b/systemtests/tests/checkpoints/etc/bareos/bareos-sd.d/director/bareos-dir.conf.in new file mode 100644 index 000000000..deef3360c --- /dev/null +++ b/systemtests/tests/checkpoints/etc/bareos/bareos-sd.d/director/bareos-dir.conf.in @@ -0,0 +1,5 @@ +Director { + Name = bareos-dir + Password = "@sd_password@" + Description = "Director, who is permitted to contact this storage daemon." +} diff --git a/systemtests/tests/checkpoints/etc/bareos/bareos-sd.d/messages/Standard.conf b/systemtests/tests/checkpoints/etc/bareos/bareos-sd.d/messages/Standard.conf new file mode 100644 index 000000000..468348e62 --- /dev/null +++ b/systemtests/tests/checkpoints/etc/bareos/bareos-sd.d/messages/Standard.conf @@ -0,0 +1,5 @@ +Messages { + Name = Standard + Director = bareos-dir = all + Description = "Send all messages to the Director." +} diff --git a/systemtests/tests/checkpoints/etc/bareos/bareos-sd.d/storage/bareos-sd.conf.in b/systemtests/tests/checkpoints/etc/bareos/bareos-sd.d/storage/bareos-sd.conf.in new file mode 100644 index 000000000..92656f4b5 --- /dev/null +++ b/systemtests/tests/checkpoints/etc/bareos/bareos-sd.d/storage/bareos-sd.conf.in @@ -0,0 +1,12 @@ +Storage { + Name = bareos-sd + Maximum Concurrent Jobs = 20 + + # remove comment from "Plugin Directory" to load plugins from specified directory. + # if "Plugin Names" is defined, only the specified plugins will be loaded, + # otherwise all storage plugins (*-sd.so) from the "Plugin Directory". + # + Working Directory = "@working_dir@" + SD Port = @sd_port@ + Checkpoint Interval = 3 +} diff --git a/systemtests/tests/checkpoints/etc/bareos/bconsole.conf.in b/systemtests/tests/checkpoints/etc/bareos/bconsole.conf.in new file mode 100644 index 000000000..50b647c1d --- /dev/null +++ b/systemtests/tests/checkpoints/etc/bareos/bconsole.conf.in @@ -0,0 +1,10 @@ +# +# Bareos User Agent (or Console) Configuration File +# + +Director { + Name = @basename@-dir + DIRport = @dir_port@ + Address = @hostname@ + Password = "@dir_password@" +} diff --git a/systemtests/tests/checkpoints/test-setup b/systemtests/tests/checkpoints/test-setup new file mode 100755 index 000000000..9f7be3d9b --- /dev/null +++ b/systemtests/tests/checkpoints/test-setup @@ -0,0 +1,40 @@ +#!/bin/bash + +# BAREOS® - Backup Archiving REcovery Open Sourced +# +# Copyright (C) 2022-2022 Bareos GmbH & Co. KG +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of version three of the GNU Affero General Public +# License as published by the Free Software Foundation and included +# in the file LICENSE. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +set -e +set -o pipefail +set -u + +#shellcheck source=../environment.in +. ./environment + +#shellcheck source=../scripts/functions +. "${rscripts}"/functions +"${rscripts}"/cleanup +"${rscripts}"/setup + +# Fill ${BackupDirectory} with data. +setup_data + +bin/bareos start + +# make sure, director is up and running. +print_debug "$(bin/bconsole <<< "status dir")" diff --git a/systemtests/tests/checkpoints/testrunner-checkpoints-on-cancel b/systemtests/tests/checkpoints/testrunner-checkpoints-on-cancel new file mode 100755 index 000000000..433337c5c --- /dev/null +++ b/systemtests/tests/checkpoints/testrunner-checkpoints-on-cancel @@ -0,0 +1,111 @@ +#!/bin/bash +set -o pipefail +set -u +# +# Cancel a backup and check that metadata is still saved with checkpoints. +# +TestName="$(basename "$(pwd)")" +export TestName + +#shellcheck source=../environment.in +. ./environment + +#shellcheck source=../scripts/functions +. "${rscripts}"/functions + +start_test + +backup_log=$tmp/cancel-backup-checkpoints.out +restore_log=$tmp/cancel-restore-checkpoints.out + +rm -f $backup_log +rm -f $restore_log + +slowjob="slow-backup-bareos-fd" + +cat <<END_OF_DATA >"$tmp/bconcmds" +@$out /dev/null +messages +@$out $backup_log +run job=$slowjob level=Full yes +quit +END_OF_DATA + +run_bconsole + +timeout=0 +timed_checkpoint="" +volume_checkpoint="" + +while [[ ${timeout} -lt 30 ]] && [[ -z $timed_checkpoint || -z $volume_checkpoint ]] +do + timed_checkpoint=$(grep -m 1 'Doing timed backup checkpoint. Next checkpoint in 3 seconds' $messagesfile) + volume_checkpoint=$(grep -m 1 'Volume changed, doing checkpoint:' "$messagesfile") + sleep 1 + ((++timeout)) +done + +# Check that a timed checkpoint was triggered +if [[ -z $timed_checkpoint ]]; then + echo "Timed checkpoint was not triggered!" + estat=1; +fi + +# Check that a checkpoint happened on a volume change +if [[ -z $volume_checkpoint ]]; then + echo "Checkpoint was not triggered on volume changes!" + estat=2; +fi + + +slowjobid=$(grep 'Job queued. JobId=' $backup_log | sed -n -e 's/^.*JobId=//p') + +cat <<END_OF_DATA >"$tmp/bconcmds" +@$out $backup_log +cancel jobid=${slowjobid} +wait +messages +@$out $restore_log +restore jobid=${slowjobid} where=$tmp/checkpoint-restores all done yes +wait +messages +quit +END_OF_DATA + +run_bconsole + +# Check that a cancel was triggered +expect_grep "Termination: Backup Canceled" \ + "$backup_log" \ + "Job was not canceled!" + +NumberOfBackedUpFiles=$(grep 'FD Files Written: ' $backup_log | sed -n -e 's/^.*Written: //p') + +# Check that part of the files were written despite the cancel +if [ $NumberOfBackedUpFiles -le 0 ]; then + echo "Checkpoint files were not correctly saved! Number of backed up files: ${NumberOfBackedUpFiles}" >&2 + estat=1 +fi + +# Check that the restore of a canceled backup works fine +expect_grep "Termination: Restore OK" \ + "$restore_log" \ + "Restore is not OK." + +expect_grep "Files Restored: ${NumberOfBackedUpFiles}" \ + "$restore_log" \ + "Restore of canceled job did not go well!" + +# Certain systems do not support multiple types for find (-type f,l) +NumberOfFilesRestored=$(find $tmp/checkpoint-restores/$tmp -type f | wc -l) +NumberOfLinksRestored=$(find $tmp/checkpoint-restores/$tmp -type l | wc -l) +NumberOfDirectoriesRestored=$(find $tmp/checkpoint-restores/$tmp -type d | wc -l) +RestoredItems=$(expr $NumberOfFilesRestored + $NumberOfLinksRestored + $NumberOfDirectoriesRestored) + +# Check that the restored files are actually there +if [ ${RestoredItems} -lt ${NumberOfBackedUpFiles} ]; then + echo "Actual restored items count not met. Items (files, links, directories) found = ${RestoredItems} , backed up files = ${NumberOfBackedUpFiles}" >&2 + estat=1 +fi + +end_test diff --git a/systemtests/tests/checkpoints/testrunner-checkpoints-on-kill b/systemtests/tests/checkpoints/testrunner-checkpoints-on-kill new file mode 100755 index 000000000..61716f050 --- /dev/null +++ b/systemtests/tests/checkpoints/testrunner-checkpoints-on-kill @@ -0,0 +1,109 @@ +#!/bin/bash +set -o pipefail +set -u +# +# Kill the daemons while running a backup. +# Check that metadata is still saved with checkpoints. +# +TestName="$(basename "$(pwd)")" +export TestName + +#shellcheck source=../environment.in +. ./environment + +#shellcheck source=../scripts/functions +. "${rscripts}"/functions + +start_test + +slowjob="slow-backup-bareos-fd" + +for daemon in "dir" "sd" "fd"; do + + backup_log=$tmp/kill-$daemon-backup-checkpoints.out + restore_log=$tmp/kill-$daemon-restore-checkpoints.out + restore_directory=$tmp/kill-$daemon-checkpoint-restores + + rm -f $backup_log + rm -f $restore_log + +cat <<END_OF_DATA >"$tmp/bconcmds" +@$out /dev/null +messages +@$out $backup_log +run job=$slowjob level=Full yes +quit +END_OF_DATA + + run_bconsole + + timeout=0 + timed_checkpoint="" + volume_checkpoint="" + + while [[ ${timeout} -lt 30 ]] && [[ -z $timed_checkpoint || -z $volume_checkpoint ]] + do + + timed_checkpoint=$(grep -m 1 'Doing timed backup checkpoint. Next checkpoint in 3 seconds' "$messagesfile") + volume_checkpoint=$(grep -m 1 'Volume changed, doing checkpoint:' "$messagesfile") + sleep 1 + ((++timeout)) + done #end while + + # Check that a timed checkpoint was triggered + if [[ -z $timed_checkpoint ]]; then + echo "ERROR: Timed checkpoint was not triggered!" + estat=1; + fi + + # Check that a checkpoint happened on a volume change + if [[ -z $volume_checkpoint ]]; then + echo "ERROR: Checkpoint was not triggered on volume changes!" + estat=2; + fi + + slowjobid=$(grep 'Job queued. JobId=' "$backup_log" | sed -n -e 's/^.*JobId=//p') + + if [ "$daemon" == "fd" ]; then + echo "Killing the FD" + pkill -KILL -f "${BAREOS_FILEDAEMON_BINARY}" + sleep 3 + ${rscripts}/bareos-ctl-fd start + fi + + if [ "$daemon" == "sd" ]; then + + echo "Killing the SD" + pkill -KILL -f "${BAREOS_STORAGEDAEMON_BINARY}" + sleep 3 + ${rscripts}/bareos-ctl-sd start + fi + if [ "$daemon" == "dir" ]; then + + echo "Killing the DIR" + pkill -KILL -f "${BAREOS_DIRECTOR_BINARY}" + sleep 3 + ${rscripts}/bareos-ctl-dir start + fi + +cat <<END_OF_DATA >"$tmp/bconcmds" +@$out $backup_log +wait +messages +@$out $restore_log +restore jobid=${slowjobid} where=$restore_directory all done yes +wait +messages +quit +END_OF_DATA + + run_bconsole + + # Check that the restore works fine + expect_grep "Termination: Restore OK" \ + "$restore_log" \ + "Restore job did not go well!" + +done #end for + +end_test diff --git a/systemtests/tests/checkpoints/testrunner-checkpoints-on-stop b/systemtests/tests/checkpoints/testrunner-checkpoints-on-stop new file mode 100755 index 000000000..68bc0a1bf --- /dev/null +++ b/systemtests/tests/checkpoints/testrunner-checkpoints-on-stop @@ -0,0 +1,104 @@ +#!/bin/bash +set -o pipefail +set -u +# +# Stop the daemons while running backup. +# Check that metadata is still saved with checkpoints. +# +TestName="$(basename "$(pwd)")" +export TestName + +#shellcheck source=../environment.in +. ./environment + +#shellcheck source=../scripts/functions +. "${rscripts}"/functions + +start_test + +backup_log=$tmp/stop-backup-checkpoints.out +restore_log=$tmp/stop-restore-checkpoints.out + +rm -f $backup_log +rm -f $restore_log + +slowjob="slow-backup-bareos-fd" + +cat <<END_OF_DATA >"$tmp/bconcmds" +@$out /dev/null +messages +@$out $backup_log +run job=$slowjob level=Full yes +quit +END_OF_DATA + +run_bconsole + +timeout=0 +timed_checkpoint="" +volume_checkpoint="" + +while [[ ${timeout} -lt 30 ]] && [[ -z $timed_checkpoint || -z $volume_checkpoint ]] +do + timed_checkpoint=$(grep -m 1 'Doing timed backup checkpoint. Next checkpoint in 3 seconds' "$messagesfile") + volume_checkpoint=$(grep -m 1 'Volume changed, doing checkpoint:' "$messagesfile") + sleep 1 + ((++timeout)) +done + +# Check that a timed checkpoint was triggered +if [[ -z $timed_checkpoint ]]; then + echo "Timed checkpoint was not triggered!" + estat=1; +fi + +# Check that a checkpoint happened on a volume change +if [[ -z $volume_checkpoint ]]; then + echo "Checkpoint was not triggered on volume changes!" + estat=2; +fi + +slowjobid=$(grep 'Job queued. JobId=' $backup_log | sed -n -e 's/^.*JobId=//p') + +bin/bareos stop + +bin/bareos start + +cat <<END_OF_DATA >"$tmp/bconcmds" +@$out $backup_log +messages +@$out $restore_log +restore jobid=${slowjobid} where=$tmp/checkpoint-restores all done yes +wait +messages +quit +END_OF_DATA + +run_bconsole + +NumberOfBackedUpFiles=$(grep 'FD Files Written: ' $backup_log | sed -n -e 's/^.*Written: //p') + +# Check that part of the files were written despite the stop +if [ $NumberOfBackedUpFiles -le 0 ]; then + echo "Checkpoint files were not correctly saved! Number of backed up files: ${NumberOfBackedUpFiles}" >&2 + estat=1 +fi + +# Check that the restore works fine +expect_grep "Termination: Restore OK" \ + "$restore_log"\ + "Restore job did not go well!" + +# Certain systems do not support multiple types for find (-type f,l) +NumberOfFilesRestored=$(find $tmp/checkpoint-restores/$tmp -type f | wc -l) +NumberOfLinksRestored=$(find $tmp/checkpoint-restores/$tmp -type l | wc -l) +NumberOfDirectoriesRestored=$(find $tmp/checkpoint-restores/$tmp -type d | wc -l) +RestoredItems=$(expr $NumberOfFilesRestored + $NumberOfLinksRestored + $NumberOfDirectoriesRestored) + +# Check that the restored files are actually there +if [ ${RestoredItems} -lt ${NumberOfBackedUpFiles} ]; then + echo "Actual restored items count not met. Items (files, links, directories) found = ${RestoredItems} , backed up files = ${NumberOfBackedUpFiles}" >&2 + estat=1 +fi + +end_test diff --git a/systemtests/tests/parallel-jobs/CMakeLists.txt b/systemtests/tests/parallel-jobs/CMakeLists.txt new file mode 100644 index 000000000..47970a2ef --- /dev/null +++ b/systemtests/tests/parallel-jobs/CMakeLists.txt @@ -0,0 +1,21 @@ +# BAREOS® - Backup Archiving REcovery Open Sourced +# +# Copyright (C) 2022-2022 Bareos GmbH & Co. KG +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of version three of the GNU Affero General Public +# License as published by the Free Software Foundation and included +# in the file LICENSE. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +get_filename_component(BASENAME ${CMAKE_CURRENT_BINARY_DIR} NAME) +create_systemtest(${SYSTEMTEST_PREFIX} ${BASENAME}) diff --git a/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/catalog/MyCatalog.conf.in b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/catalog/MyCatalog.conf.in new file mode 100644 index 000000000..3c3385945 --- /dev/null +++ b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/catalog/MyCatalog.conf.in @@ -0,0 +1,6 @@ +Catalog { + Name = MyCatalog + dbname = "@db_name@" + dbuser = "@db_user@" + dbpassword = "@db_password@" +} diff --git a/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/client/bareos-fd.conf.in b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/client/bareos-fd.conf.in new file mode 100644 index 000000000..9341d2557 --- /dev/null +++ b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/client/bareos-fd.conf.in @@ -0,0 +1,8 @@ +Client { + Name = bareos-fd + Description = "Client resource of the Director itself." + Address = @hostname@ + Password = "@fd_password@" # password for FileDaemon + FD PORT = @fd_port@ + MaximumConcurrentJobs = 10 +} diff --git a/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/director/bareos-dir.conf.in b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/director/bareos-dir.conf.in new file mode 100644 index 000000000..266d120dd --- /dev/null +++ b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/director/bareos-dir.conf.in @@ -0,0 +1,26 @@ +Director { # define myself + Name = bareos-dir + QueryFile = "@scriptdir@/query.sql" + Maximum Concurrent Jobs = 10 + Password = "@dir_password@" # Console password + Messages = Daemon + Auditing = yes + + # Enable the Heartbeat if you experience connection losses + # (eg. because of your router or firewall configuration). + # Additionally the Heartbeat can be enabled in bareos-sd and bareos-fd. + # + # Heartbeat Interval = 1 min + + # remove comment in next line to load dynamic backends from specified directory + Backend Directory = @backenddir@ + + # remove comment from "Plugin Directory" to load plugins from specified directory. + # if "Plugin Names" is defined, only the specified plugins will be loaded, + # otherwise all director plugins (*-dir.so) from the "Plugin Directory". + # + # Plugin Directory = "@python_plugin_module_src_dir@" + # Plugin Names = "" + Working Directory = "@working_dir@" + DirPort = @dir_port@ +} diff --git a/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/fileset/Catalog.conf.in b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/fileset/Catalog.conf.in new file mode 100644 index 000000000..c7cdc433f --- /dev/null +++ b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/fileset/Catalog.conf.in @@ -0,0 +1,11 @@ +FileSet { + Name = "Catalog" + Description = "Backup the catalog dump and Bareos configuration files." + Include { + Options { + signature = MD5 + } + File = "@working_dir@/@db_name@.sql" # database dump + File = "@confdir@" # configuration + } +} diff --git a/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/fileset/SelfTest.conf.in b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/fileset/SelfTest.conf.in new file mode 100644 index 000000000..be175b9a9 --- /dev/null +++ b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/fileset/SelfTest.conf.in @@ -0,0 +1,20 @@ +FileSet { + Name = "SelfTest" + Description = "fileset just to backup some files for selftest" + Include { + Options { + Signature = MD5 # calculate md5 checksum per file + fstype = ext2 + fstype = ext3 + fstype = ext4 + fstype = overlay + fstype = jfs + fstype = ufs + fstype = xfs + fstype = zfs + fstype = btrfs + } + #File = "@sbindir@" + File=<@tmpdir@/file-list + } +} diff --git a/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/job/BackupCatalog.conf.in b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/job/BackupCatalog.conf.in new file mode 100644 index 000000000..1da2a7af6 --- /dev/null +++ b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/job/BackupCatalog.conf.in @@ -0,0 +1,20 @@ +Job { + Name = "BackupCatalog" + Description = "Backup the catalog database (after the nightly save)" + JobDefs = "DefaultJob" + Level = Full + FileSet="Catalog" + + # This creates an ASCII copy of the catalog + # Arguments to make_catalog_backup.pl are: + # make_catalog_backup.pl <catalog-name> + RunBeforeJob = "@scriptdir@/make_catalog_backup.pl MyCatalog" + + # This deletes the copy of the catalog + RunAfterJob = "@scriptdir@/delete_catalog_backup" + + # This sends the bootstrap via mail for disaster recovery. + # Should be sent to another system, please change recipient accordingly + Write Bootstrap = "|@bindir@/bsmtp -h @smtp_host@ -f \"\(Bareos\) \" -s \"Bootstrap for Job %j\" @job_email@" # (#01) + Priority = 11 # run after main backup +} diff --git a/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/job/RestoreFiles.conf.in b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/job/RestoreFiles.conf.in new file mode 100644 index 000000000..89256864d --- /dev/null +++ b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/job/RestoreFiles.conf.in @@ -0,0 +1,11 @@ +Job { + Name = "RestoreFiles" + Description = "Standard Restore template. Only one such job is needed for all standard Jobs/Clients/Storage ..." + Type = Restore + Client = bareos-fd + FileSet = SelfTest + Storage = File + Pool = Incremental + Messages = Standard + Where = @tmp@/bareos-restores +} diff --git a/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/job/backup-bareos-fd.conf b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/job/backup-bareos-fd.conf new file mode 100644 index 000000000..6ad780134 --- /dev/null +++ b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/job/backup-bareos-fd.conf @@ -0,0 +1,6 @@ +Job { + Name = "backup-bareos-fd" + JobDefs = "DefaultJob" + Client = "bareos-fd" + MaximumConcurrentJobs = 10 +} diff --git a/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/jobdefs/DefaultJob.conf.in b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/jobdefs/DefaultJob.conf.in new file mode 100644 index 000000000..563126477 --- /dev/null +++ b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/jobdefs/DefaultJob.conf.in @@ -0,0 +1,15 @@ +JobDefs { + Name = "DefaultJob" + Type = Backup + Level = Incremental + Client = bareos-fd + FileSet = "SelfTest" + Storage = File + Messages = Standard + Pool = Incremental + Priority = 10 + Write Bootstrap = "@working_dir@/%c.bsr" + Full Backup Pool = Full # write Full Backups into "Full" Pool + Differential Backup Pool = Differential # write Diff Backups into "Differential" Pool + Incremental Backup Pool = Incremental # write Incr Backups into "Incremental" Pool +} diff --git a/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/messages/Daemon.conf.in b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/messages/Daemon.conf.in new file mode 100644 index 000000000..cf6a8cfa1 --- /dev/null +++ b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/messages/Daemon.conf.in @@ -0,0 +1,7 @@ +Messages { + Name = Daemon + Description = "Message delivery for daemon messages (no job)." + console = all, !skipped, !saved, !audit + append = "@logdir@/bareos.log" = all, !skipped, !audit + append = "@logdir@/bareos-audit.log" = audit +} diff --git a/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/messages/Standard.conf.in b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/messages/Standard.conf.in new file mode 100644 index 000000000..b3556ba8c --- /dev/null +++ b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/messages/Standard.conf.in @@ -0,0 +1,7 @@ +Messages { + Name = Standard + Description = "Reasonable message delivery -- send most everything to email address and to the console." + console = all, !skipped, !saved, !audit + append = "@logdir@/bareos.log" = all, !skipped, !saved, !audit + catalog = all, !skipped, !saved, !audit +} diff --git a/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/pool/Differential.conf b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/pool/Differential.conf new file mode 100644 index 000000000..25ce24821 --- /dev/null +++ b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/pool/Differential.conf @@ -0,0 +1,10 @@ +Pool { + Name = Differential + Pool Type = Backup + Recycle = yes # Bareos can automatically recycle Volumes + AutoPrune = yes # Prune expired volumes + Volume Retention = 90 days # How long should the Differential Backups be kept? (#09) + Maximum Volume Bytes = 10G # Limit Volume size to something reasonable + Maximum Volumes = 100 # Limit number of Volumes in Pool + Label Format = "Differential-" # Volumes will be labeled "Differential-<volume-id>" +} diff --git a/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/pool/Full.conf b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/pool/Full.conf new file mode 100644 index 000000000..867fc66b4 --- /dev/null +++ b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/pool/Full.conf @@ -0,0 +1,10 @@ +Pool { + Name = Full + Pool Type = Backup + Recycle = yes # Bareos can automatically recycle Volumes + AutoPrune = yes # Prune expired volumes + Volume Retention = 365 days # How long should the Full Backups be kept? (#06) + Maximum Volume Bytes = 50G # Limit Volume size to something reasonable + Maximum Volumes = 100 # Limit number of Volumes in Pool + Label Format = "Full-" # Volumes will be labeled "Full-<volume-id>" +} diff --git a/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/pool/FullSmallvolumes.conf b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/pool/FullSmallvolumes.conf new file mode 100644 index 000000000..aa8d7b5eb --- /dev/null +++ b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/pool/FullSmallvolumes.conf @@ -0,0 +1,11 @@ +Pool { + Name = SmallFull + Pool Type = Backup + Recycle = yes + AutoPrune = yes + Volume Retention = 365 days + Maximum Volume Bytes = 32k + Maximum Volumes = 100 + Label Format = "SmallFull-" + Maximum Block Size = 16K +} diff --git a/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/pool/Incremental.conf b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/pool/Incremental.conf new file mode 100644 index 000000000..f4dbbab66 --- /dev/null +++ b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/pool/Incremental.conf @@ -0,0 +1,10 @@ +Pool { + Name = Incremental + Pool Type = Backup + Recycle = yes # Bareos can automatically recycle Volumes + AutoPrune = yes # Prune expired volumes + Volume Retention = 30 days # How long should the Incremental Backups be kept? (#12) + Maximum Volume Bytes = 1G # Limit Volume size to something reasonable + Maximum Volumes = 100 # Limit number of Volumes in Pool + Label Format = "Incremental-" # Volumes will be labeled "Incremental-<volume-id>" +} diff --git a/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/pool/Scratch.conf b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/pool/Scratch.conf new file mode 100644 index 000000000..3a489b198 --- /dev/null +++ b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/pool/Scratch.conf @@ -0,0 +1,4 @@ +Pool { + Name = Scratch + Pool Type = Scratch +} diff --git a/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/profile/operator.conf b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/profile/operator.conf new file mode 100644 index 000000000..6edd0166d --- /dev/null +++ b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/profile/operator.conf @@ -0,0 +1,18 @@ +Profile { + Name = operator + Description = "Profile allowing normal Bareos operations." + + Command ACL = !.bvfs_clear_cache, !.exit, !.sql + Command ACL = !configure, !create, !delete, !purge, !prune, !sqlquery, !umount, !unmount + Command ACL = *all* + + Catalog ACL = *all* + Client ACL = *all* + FileSet ACL = *all* + Job ACL = *all* + Plugin Options ACL = *all* + Pool ACL = *all* + Schedule ACL = *all* + Storage ACL = *all* + Where ACL = *all* +} diff --git a/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/storage/File.conf.in b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/storage/File.conf.in new file mode 100644 index 000000000..6d914ac0b --- /dev/null +++ b/systemtests/tests/parallel-jobs/etc/bareos/bareos-dir.d/storage/File.conf.in @@ -0,0 +1,9 @@ +Storage { + Name = File + Address = @hostname@ + Password = "@sd_password@" + Device = FileStorage + Media Type = File + SD Port = @sd_port@ + MaximumConcurrentJobs = 10 +} diff --git a/systemtests/tests/parallel-jobs/etc/bareos/bareos-fd.d/client/myself.conf.in b/systemtests/tests/parallel-jobs/etc/bareos/bareos-fd.d/client/myself.conf.in new file mode 100644 index 000000000..6439fe84d --- /dev/null +++ b/systemtests/tests/parallel-jobs/etc/bareos/bareos-fd.d/client/myself.conf.in @@ -0,0 +1,19 @@ +Client { + Name = @basename@-fd + Maximum Concurrent Jobs = 20 + + # remove comment from "Plugin Directory" to load plugins from specified directory. + # if "Plugin Names" is defined, only the specified plugins will be loaded, + # otherwise all filedaemon plugins (*-fd.so) from the "Plugin Directory". + # + # Plugin Directory = "@python_plugin_module_src_fd@" + # Plugin Names = "" + + # if compatible is set to yes, we are compatible with bacula + # if set to no, new bareos features are enabled which is the default + # compatible = yes + + Working Directory = "@working_dir@" + FD Port = @fd_port@ + +} diff --git a/systemtests/tests/parallel-jobs/etc/bareos/bareos-fd.d/director/bareos-dir.conf.in b/systemtests/tests/parallel-jobs/etc/bareos/bareos-fd.d/director/bareos-dir.conf.in new file mode 100644 index 000000000..c8dc7085a --- /dev/null +++ b/systemtests/tests/parallel-jobs/etc/bareos/bareos-fd.d/director/bareos-dir.conf.in @@ -0,0 +1,5 @@ +Director { + Name = bareos-dir + Password = "@fd_password@" + Description = "Allow the configured Director to access this file daemon." +} diff --git a/systemtests/tests/parallel-jobs/etc/bareos/bareos-fd.d/messages/Standard.conf b/systemtests/tests/parallel-jobs/etc/bareos/bareos-fd.d/messages/Standard.conf new file mode 100644 index 000000000..97788e005 --- /dev/null +++ b/systemtests/tests/parallel-jobs/etc/bareos/bareos-fd.d/messages/Standard.conf @@ -0,0 +1,5 @@ +Messages { + Name = Standard + Director = bareos-dir = all, !skipped, !restored + Description = "Send relevant messages to the Director." +} diff --git a/systemtests/tests/parallel-jobs/etc/bareos/bareos-sd.d/device/FileStorage.conf b/systemtests/tests/parallel-jobs/etc/bareos/bareos-sd.d/device/FileStorage.conf new file mode 100644 index 000000000..11a639bc6 --- /dev/null +++ b/systemtests/tests/parallel-jobs/etc/bareos/bareos-sd.d/device/FileStorage.conf @@ -0,0 +1,11 @@ +Device { + Name = FileStorage + Media Type = File + Archive Device = storage + LabelMedia = yes; # lets Bareos label unlabeled media + Random Access = yes; + AutomaticMount = yes; # when device opened, read it + RemovableMedia = no; + AlwaysOpen = no; + Description = "File device. A connecting Director must have the same Name and MediaType." +} diff --git a/systemtests/tests/parallel-jobs/etc/bareos/bareos-sd.d/director/bareos-dir.conf.in b/systemtests/tests/parallel-jobs/etc/bareos/bareos-sd.d/director/bareos-dir.conf.in new file mode 100644 index 000000000..deef3360c --- /dev/null +++ b/systemtests/tests/parallel-jobs/etc/bareos/bareos-sd.d/director/bareos-dir.conf.in @@ -0,0 +1,5 @@ +Director { + Name = bareos-dir + Password = "@sd_password@" + Description = "Director, who is permitted to contact this storage daemon." +} diff --git a/systemtests/tests/parallel-jobs/etc/bareos/bareos-sd.d/messages/Standard.conf b/systemtests/tests/parallel-jobs/etc/bareos/bareos-sd.d/messages/Standard.conf new file mode 100644 index 000000000..468348e62 --- /dev/null +++ b/systemtests/tests/parallel-jobs/etc/bareos/bareos-sd.d/messages/Standard.conf @@ -0,0 +1,5 @@ +Messages { + Name = Standard + Director = bareos-dir = all + Description = "Send all messages to the Director." +} diff --git a/systemtests/tests/parallel-jobs/etc/bareos/bareos-sd.d/storage/bareos-sd.conf.in b/systemtests/tests/parallel-jobs/etc/bareos/bareos-sd.d/storage/bareos-sd.conf.in new file mode 100644 index 000000000..d555776e0 --- /dev/null +++ b/systemtests/tests/parallel-jobs/etc/bareos/bareos-sd.d/storage/bareos-sd.conf.in @@ -0,0 +1,11 @@ +Storage { + Name = bareos-sd + Maximum Concurrent Jobs = 20 + + # remove comment from "Plugin Directory" to load plugins from specified directory. + # if "Plugin Names" is defined, only the specified plugins will be loaded, + # otherwise all storage plugins (*-sd.so) from the "Plugin Directory". + # + Working Directory = "@working_dir@" + SD Port = @sd_port@ +} diff --git a/systemtests/tests/parallel-jobs/etc/bareos/bconsole.conf.in b/systemtests/tests/parallel-jobs/etc/bareos/bconsole.conf.in new file mode 100644 index 000000000..50b647c1d --- /dev/null +++ b/systemtests/tests/parallel-jobs/etc/bareos/bconsole.conf.in @@ -0,0 +1,10 @@ +# +# Bareos User Agent (or Console) Configuration File +# + +Director { + Name = @basename@-dir + DIRport = @dir_port@ + Address = @hostname@ + Password = "@dir_password@" +} diff --git a/systemtests/tests/parallel-jobs/parallel b/systemtests/tests/parallel-jobs/parallel new file mode 100755 index 000000000..38996bda5 --- /dev/null +++ b/systemtests/tests/parallel-jobs/parallel @@ -0,0 +1,66 @@ +#!/bin/bash +set -e +set -o pipefail +set -u +# +# Run a simple backup +# then restore it. +# +TestName="$(basename "$(pwd)")" +export TestName + +backup1=backup-bareos-fd +backup2=backup-bareos-fd +backup3=backup-bareos-fd + +#shellcheck source=../environment.in +. ./environment + +#shellcheck source=../scripts/functions +. "${rscripts}"/functions + + +echo "/home/alaa/Documents/smallfiles/" >"$tmp/file-list" + +start_test + +cat <<END_OF_DATA >"$tmp/bconcmds" +@$out /dev/null +messages +@$out $tmp/paralell-backup.out +run job=${backup1} level=Full yes +run job=${backup1} level=Full yes +run job=${backup1} level=Full yes +wait +messages + +@$out $tmp/paralell-restore.out +restore jobid=1 all done +1 +yes +restore jobid=2 all done +2 +yes +restore jobid=3 all done +3 +yes +wait +messages +quit +END_OF_DATA + +#run job=restore1 jobid=1 yes +#run job=restore2 jobid=2 yes +#run job=restore3 jobid=3 yes + +run_bconsole + +for i in 1 2 3; do + diffr=$(diff -qr ~/Documents/smallfiles tmp/restore$i/home/alaa/Documents/smallfiles) + echo $diffr + if [ "${diffr}" != "" ]; then + echo "bad diff backup $i" + fi +done + +end_test diff --git a/systemtests/tests/parallel-jobs/test-setup b/systemtests/tests/parallel-jobs/test-setup new file mode 100755 index 000000000..9f7be3d9b --- /dev/null +++ b/systemtests/tests/parallel-jobs/test-setup @@ -0,0 +1,40 @@ +#!/bin/bash + +# BAREOS® - Backup Archiving REcovery Open Sourced +# +# Copyright (C) 2022-2022 Bareos GmbH & Co. KG +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of version three of the GNU Affero General Public +# License as published by the Free Software Foundation and included +# in the file LICENSE. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +set -e +set -o pipefail +set -u + +#shellcheck source=../environment.in +. ./environment + +#shellcheck source=../scripts/functions +. "${rscripts}"/functions +"${rscripts}"/cleanup +"${rscripts}"/setup + +# Fill ${BackupDirectory} with data. +setup_data + +bin/bareos start + +# make sure, director is up and running. +print_debug "$(bin/bconsole <<< "status dir")" diff --git a/systemtests/tests/parallel-jobs/testrunner-parallel-jobs b/systemtests/tests/parallel-jobs/testrunner-parallel-jobs new file mode 100755 index 000000000..2d8e3646e --- /dev/null +++ b/systemtests/tests/parallel-jobs/testrunner-parallel-jobs @@ -0,0 +1,48 @@ +#!/bin/bash +set -e +set -o pipefail +set -u +# +# Run 3 backups in parallel and then restore one of them +# +TestName="$(basename "$(pwd)")" +export TestName + +backup=backup-bareos-fd + +#shellcheck source=../environment.in +. ./environment + +#shellcheck source=../scripts/functions +. "${rscripts}"/functions + +backup_log=$tmp/parallel-backup.out +restore_log=$tmp/paralell-restore.out + +rm -f $backup_log +rm -f $restore_log + +start_test + +cat <<END_OF_DATA >"$tmp/bconcmds" +@$out /dev/null +messages +@$out $backup_log +run job=${backup} level=Full yes +run job=${backup} level=Full yes +run job=${backup} level=Full yes +wait +messages + +@$out $restore_log +restore jobid=1 all done yes +wait +messages +quit +END_OF_DATA + +run_bconsole + +check_restore_diff "${BackupDirectory}" + +end_test diff --git a/systemtests/tests/stresstest/CMakeLists.txt b/systemtests/tests/stresstest/CMakeLists.txt new file mode 100644 index 000000000..75c7186c3 --- /dev/null +++ b/systemtests/tests/stresstest/CMakeLists.txt @@ -0,0 +1,21 @@ +# BAREOS® - Backup Archiving REcovery Open Sourced +# +# Copyright (C) 2022-2022 Bareos GmbH & Co. KG +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of version three of the GNU Affero General Public +# License as published by the Free Software Foundation and included +# in the file LICENSE. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +get_filename_component(BASENAME ${CMAKE_CURRENT_BINARY_DIR} NAME) +create_systemtest(${SYSTEMTEST_PREFIX} ${BASENAME} DISABLED) diff --git a/systemtests/tests/stresstest/cloneandcopykernelcode b/systemtests/tests/stresstest/cloneandcopykernelcode new file mode 100644 index 000000000..635038325 --- /dev/null +++ b/systemtests/tests/stresstest/cloneandcopykernelcode @@ -0,0 +1,36 @@ +#!/bin/bash + +# BAREOS® - Backup Archiving REcovery Open Sourced +# +# Copyright (C) 2022-2022 Bareos GmbH & Co. KG +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of version three of the GNU Affero General Public +# License as published by the Free Software Foundation and included +# in the file LICENSE. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +set -e +set -o pipefail + +# clone the linux kernel code from github and make 10 copies of it +# it would amount to 75GB of data, and around 1M files + +mkdir kernelcopies +cd kernelcopies +git clone https://www.github.com/torvalds/linux + +for i in 1..15; do + cp -r linux linux$i +done + +cd ../ diff --git a/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/catalog/MyCatalog.conf.in b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/catalog/MyCatalog.conf.in new file mode 100644 index 000000000..3c3385945 --- /dev/null +++ b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/catalog/MyCatalog.conf.in @@ -0,0 +1,6 @@ +Catalog { + Name = MyCatalog + dbname = "@db_name@" + dbuser = "@db_user@" + dbpassword = "@db_password@" +} diff --git a/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/client/bareos-fd.conf.in b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/client/bareos-fd.conf.in new file mode 100644 index 000000000..59b617009 --- /dev/null +++ b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/client/bareos-fd.conf.in @@ -0,0 +1,7 @@ +Client { + Name = bareos-fd + Description = "Client resource of the Director itself." + Address = @hostname@ + Password = "@fd_password@" # password for FileDaemon + FD PORT = @fd_port@ +} diff --git a/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/director/bareos-dir.conf.in b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/director/bareos-dir.conf.in new file mode 100644 index 000000000..266d120dd --- /dev/null +++ b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/director/bareos-dir.conf.in @@ -0,0 +1,26 @@ +Director { # define myself + Name = bareos-dir + QueryFile = "@scriptdir@/query.sql" + Maximum Concurrent Jobs = 10 + Password = "@dir_password@" # Console password + Messages = Daemon + Auditing = yes + + # Enable the Heartbeat if you experience connection losses + # (eg. because of your router or firewall configuration). + # Additionally the Heartbeat can be enabled in bareos-sd and bareos-fd. + # + # Heartbeat Interval = 1 min + + # remove comment in next line to load dynamic backends from specified directory + Backend Directory = @backenddir@ + + # remove comment from "Plugin Directory" to load plugins from specified directory. + # if "Plugin Names" is defined, only the specified plugins will be loaded, + # otherwise all director plugins (*-dir.so) from the "Plugin Directory". + # + # Plugin Directory = "@python_plugin_module_src_dir@" + # Plugin Names = "" + Working Directory = "@working_dir@" + DirPort = @dir_port@ +} diff --git a/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/fileset/Catalog.conf.in b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/fileset/Catalog.conf.in new file mode 100644 index 000000000..c7cdc433f --- /dev/null +++ b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/fileset/Catalog.conf.in @@ -0,0 +1,11 @@ +FileSet { + Name = "Catalog" + Description = "Backup the catalog dump and Bareos configuration files." + Include { + Options { + signature = MD5 + } + File = "@working_dir@/@db_name@.sql" # database dump + File = "@confdir@" # configuration + } +} diff --git a/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/fileset/SelfTest.conf.in b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/fileset/SelfTest.conf.in new file mode 100644 index 000000000..be175b9a9 --- /dev/null +++ b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/fileset/SelfTest.conf.in @@ -0,0 +1,20 @@ +FileSet { + Name = "SelfTest" + Description = "fileset just to backup some files for selftest" + Include { + Options { + Signature = MD5 # calculate md5 checksum per file + fstype = ext2 + fstype = ext3 + fstype = ext4 + fstype = overlay + fstype = jfs + fstype = ufs + fstype = xfs + fstype = zfs + fstype = btrfs + } + #File = "@sbindir@" + File=<@tmpdir@/file-list + } +} diff --git a/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/job/BackupCatalog.conf.in b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/job/BackupCatalog.conf.in new file mode 100644 index 000000000..1da2a7af6 --- /dev/null +++ b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/job/BackupCatalog.conf.in @@ -0,0 +1,20 @@ +Job { + Name = "BackupCatalog" + Description = "Backup the catalog database (after the nightly save)" + JobDefs = "DefaultJob" + Level = Full + FileSet="Catalog" + + # This creates an ASCII copy of the catalog + # Arguments to make_catalog_backup.pl are: + # make_catalog_backup.pl <catalog-name> + RunBeforeJob = "@scriptdir@/make_catalog_backup.pl MyCatalog" + + # This deletes the copy of the catalog + RunAfterJob = "@scriptdir@/delete_catalog_backup" + + # This sends the bootstrap via mail for disaster recovery. + # Should be sent to another system, please change recipient accordingly + Write Bootstrap = "|@bindir@/bsmtp -h @smtp_host@ -f \"\(Bareos\) \" -s \"Bootstrap for Job %j\" @job_email@" # (#01) + Priority = 11 # run after main backup +} diff --git a/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/job/RestoreFiles.conf.in b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/job/RestoreFiles.conf.in new file mode 100644 index 000000000..89256864d --- /dev/null +++ b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/job/RestoreFiles.conf.in @@ -0,0 +1,11 @@ +Job { + Name = "RestoreFiles" + Description = "Standard Restore template. Only one such job is needed for all standard Jobs/Clients/Storage ..." + Type = Restore + Client = bareos-fd + FileSet = SelfTest + Storage = File + Pool = Incremental + Messages = Standard + Where = @tmp@/bareos-restores +} diff --git a/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/job/backup-bareos-fd.conf b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/job/backup-bareos-fd.conf new file mode 100644 index 000000000..ca1891f96 --- /dev/null +++ b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/job/backup-bareos-fd.conf @@ -0,0 +1,5 @@ +Job { + Name = "backup-bareos-fd" + JobDefs = "DefaultJob" + Client = "bareos-fd" +} diff --git a/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/job/slow-backup-bareos-fd.conf b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/job/slow-backup-bareos-fd.conf new file mode 100644 index 000000000..b9f416f53 --- /dev/null +++ b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/job/slow-backup-bareos-fd.conf @@ -0,0 +1,12 @@ +Job { + Name = "slow-backup-bareos-fd" + Type = Backup + Level = Full + Client = bareos-fd + FileSet = "SelfTest" + Storage = File + Messages = Standard + Pool = SmallFull + Full Backup Pool = SmallFull + Maximum Bandwidth = 10K +} diff --git a/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/jobdefs/DefaultJob.conf.in b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/jobdefs/DefaultJob.conf.in new file mode 100644 index 000000000..563126477 --- /dev/null +++ b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/jobdefs/DefaultJob.conf.in @@ -0,0 +1,15 @@ +JobDefs { + Name = "DefaultJob" + Type = Backup + Level = Incremental + Client = bareos-fd + FileSet = "SelfTest" + Storage = File + Messages = Standard + Pool = Incremental + Priority = 10 + Write Bootstrap = "@working_dir@/%c.bsr" + Full Backup Pool = Full # write Full Backups into "Full" Pool + Differential Backup Pool = Differential # write Diff Backups into "Differential" Pool + Incremental Backup Pool = Incremental # write Incr Backups into "Incremental" Pool +} diff --git a/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/messages/Daemon.conf.in b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/messages/Daemon.conf.in new file mode 100644 index 000000000..cf6a8cfa1 --- /dev/null +++ b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/messages/Daemon.conf.in @@ -0,0 +1,7 @@ +Messages { + Name = Daemon + Description = "Message delivery for daemon messages (no job)." + console = all, !skipped, !saved, !audit + append = "@logdir@/bareos.log" = all, !skipped, !audit + append = "@logdir@/bareos-audit.log" = audit +} diff --git a/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/messages/Standard.conf.in b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/messages/Standard.conf.in new file mode 100644 index 000000000..b3556ba8c --- /dev/null +++ b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/messages/Standard.conf.in @@ -0,0 +1,7 @@ +Messages { + Name = Standard + Description = "Reasonable message delivery -- send most everything to email address and to the console." + console = all, !skipped, !saved, !audit + append = "@logdir@/bareos.log" = all, !skipped, !saved, !audit + catalog = all, !skipped, !saved, !audit +} diff --git a/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/pool/Differential.conf b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/pool/Differential.conf new file mode 100644 index 000000000..25ce24821 --- /dev/null +++ b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/pool/Differential.conf @@ -0,0 +1,10 @@ +Pool { + Name = Differential + Pool Type = Backup + Recycle = yes # Bareos can automatically recycle Volumes + AutoPrune = yes # Prune expired volumes + Volume Retention = 90 days # How long should the Differential Backups be kept? (#09) + Maximum Volume Bytes = 10G # Limit Volume size to something reasonable + Maximum Volumes = 100 # Limit number of Volumes in Pool + Label Format = "Differential-" # Volumes will be labeled "Differential-<volume-id>" +} diff --git a/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/pool/Full.conf b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/pool/Full.conf new file mode 100644 index 000000000..867fc66b4 --- /dev/null +++ b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/pool/Full.conf @@ -0,0 +1,10 @@ +Pool { + Name = Full + Pool Type = Backup + Recycle = yes # Bareos can automatically recycle Volumes + AutoPrune = yes # Prune expired volumes + Volume Retention = 365 days # How long should the Full Backups be kept? (#06) + Maximum Volume Bytes = 50G # Limit Volume size to something reasonable + Maximum Volumes = 100 # Limit number of Volumes in Pool + Label Format = "Full-" # Volumes will be labeled "Full-<volume-id>" +} diff --git a/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/pool/FullSmallvolumes.conf b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/pool/FullSmallvolumes.conf new file mode 100644 index 000000000..aa8d7b5eb --- /dev/null +++ b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/pool/FullSmallvolumes.conf @@ -0,0 +1,11 @@ +Pool { + Name = SmallFull + Pool Type = Backup + Recycle = yes + AutoPrune = yes + Volume Retention = 365 days + Maximum Volume Bytes = 32k + Maximum Volumes = 100 + Label Format = "SmallFull-" + Maximum Block Size = 16K +} diff --git a/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/pool/Incremental.conf b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/pool/Incremental.conf new file mode 100644 index 000000000..f4dbbab66 --- /dev/null +++ b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/pool/Incremental.conf @@ -0,0 +1,10 @@ +Pool { + Name = Incremental + Pool Type = Backup + Recycle = yes # Bareos can automatically recycle Volumes + AutoPrune = yes # Prune expired volumes + Volume Retention = 30 days # How long should the Incremental Backups be kept? (#12) + Maximum Volume Bytes = 1G # Limit Volume size to something reasonable + Maximum Volumes = 100 # Limit number of Volumes in Pool + Label Format = "Incremental-" # Volumes will be labeled "Incremental-<volume-id>" +} diff --git a/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/pool/Scratch.conf b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/pool/Scratch.conf new file mode 100644 index 000000000..3a489b198 --- /dev/null +++ b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/pool/Scratch.conf @@ -0,0 +1,4 @@ +Pool { + Name = Scratch + Pool Type = Scratch +} diff --git a/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/profile/operator.conf b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/profile/operator.conf new file mode 100644 index 000000000..6edd0166d --- /dev/null +++ b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/profile/operator.conf @@ -0,0 +1,18 @@ +Profile { + Name = operator + Description = "Profile allowing normal Bareos operations." + + Command ACL = !.bvfs_clear_cache, !.exit, !.sql + Command ACL = !configure, !create, !delete, !purge, !prune, !sqlquery, !umount, !unmount + Command ACL = *all* + + Catalog ACL = *all* + Client ACL = *all* + FileSet ACL = *all* + Job ACL = *all* + Plugin Options ACL = *all* + Pool ACL = *all* + Schedule ACL = *all* + Storage ACL = *all* + Where ACL = *all* +} diff --git a/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/storage/File.conf.in b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/storage/File.conf.in new file mode 100644 index 000000000..a2622f719 --- /dev/null +++ b/systemtests/tests/stresstest/etc/bareos/bareos-dir.d/storage/File.conf.in @@ -0,0 +1,8 @@ +Storage { + Name = File + Address = @hostname@ + Password = "@sd_password@" + Device = FileStorage + Media Type = File + SD Port = @sd_port@ +} diff --git a/systemtests/tests/stresstest/etc/bareos/bareos-fd.d/client/myself.conf.in b/systemtests/tests/stresstest/etc/bareos/bareos-fd.d/client/myself.conf.in new file mode 100644 index 000000000..6439fe84d --- /dev/null +++ b/systemtests/tests/stresstest/etc/bareos/bareos-fd.d/client/myself.conf.in @@ -0,0 +1,19 @@ +Client { + Name = @basename@-fd + Maximum Concurrent Jobs = 20 + + # remove comment from "Plugin Directory" to load plugins from specified directory. + # if "Plugin Names" is defined, only the specified plugins will be loaded, + # otherwise all filedaemon plugins (*-fd.so) from the "Plugin Directory". + # + # Plugin Directory = "@python_plugin_module_src_fd@" + # Plugin Names = "" + + # if compatible is set to yes, we are compatible with bacula + # if set to no, new bareos features are enabled which is the default + # compatible = yes + + Working Directory = "@working_dir@" + FD Port = @fd_port@ + +} diff --git a/systemtests/tests/stresstest/etc/bareos/bareos-fd.d/director/bareos-dir.conf.in b/systemtests/tests/stresstest/etc/bareos/bareos-fd.d/director/bareos-dir.conf.in new file mode 100644 index 000000000..c8dc7085a --- /dev/null +++ b/systemtests/tests/stresstest/etc/bareos/bareos-fd.d/director/bareos-dir.conf.in @@ -0,0 +1,5 @@ +Director { + Name = bareos-dir + Password = "@fd_password@" + Description = "Allow the configured Director to access this file daemon." +} diff --git a/systemtests/tests/stresstest/etc/bareos/bareos-fd.d/messages/Standard.conf b/systemtests/tests/stresstest/etc/bareos/bareos-fd.d/messages/Standard.conf new file mode 100644 index 000000000..97788e005 --- /dev/null +++ b/systemtests/tests/stresstest/etc/bareos/bareos-fd.d/messages/Standard.conf @@ -0,0 +1,5 @@ +Messages { + Name = Standard + Director = bareos-dir = all, !skipped, !restored + Description = "Send relevant messages to the Director." +} diff --git a/systemtests/tests/stresstest/etc/bareos/bareos-sd.d/device/FileStorage.conf b/systemtests/tests/stresstest/etc/bareos/bareos-sd.d/device/FileStorage.conf new file mode 100644 index 000000000..11a639bc6 --- /dev/null +++ b/systemtests/tests/stresstest/etc/bareos/bareos-sd.d/device/FileStorage.conf @@ -0,0 +1,11 @@ +Device { + Name = FileStorage + Media Type = File + Archive Device = storage + LabelMedia = yes; # lets Bareos label unlabeled media + Random Access = yes; + AutomaticMount = yes; # when device opened, read it + RemovableMedia = no; + AlwaysOpen = no; + Description = "File device. A connecting Director must have the same Name and MediaType." +} diff --git a/systemtests/tests/stresstest/etc/bareos/bareos-sd.d/director/bareos-dir.conf.in b/systemtests/tests/stresstest/etc/bareos/bareos-sd.d/director/bareos-dir.conf.in new file mode 100644 index 000000000..deef3360c --- /dev/null +++ b/systemtests/tests/stresstest/etc/bareos/bareos-sd.d/director/bareos-dir.conf.in @@ -0,0 +1,5 @@ +Director { + Name = bareos-dir + Password = "@sd_password@" + Description = "Director, who is permitted to contact this storage daemon." +} diff --git a/systemtests/tests/stresstest/etc/bareos/bareos-sd.d/messages/Standard.conf b/systemtests/tests/stresstest/etc/bareos/bareos-sd.d/messages/Standard.conf new file mode 100644 index 000000000..468348e62 --- /dev/null +++ b/systemtests/tests/stresstest/etc/bareos/bareos-sd.d/messages/Standard.conf @@ -0,0 +1,5 @@ +Messages { + Name = Standard + Director = bareos-dir = all + Description = "Send all messages to the Director." +} diff --git a/systemtests/tests/stresstest/etc/bareos/bareos-sd.d/storage/bareos-sd.conf.in b/systemtests/tests/stresstest/etc/bareos/bareos-sd.d/storage/bareos-sd.conf.in new file mode 100644 index 000000000..8847967d8 --- /dev/null +++ b/systemtests/tests/stresstest/etc/bareos/bareos-sd.d/storage/bareos-sd.conf.in @@ -0,0 +1,12 @@ +Storage { + Name = bareos-sd + Maximum Concurrent Jobs = 20 + + # remove comment from "Plugin Directory" to load plugins from specified directory. + # if "Plugin Names" is defined, only the specified plugins will be loaded, + # otherwise all storage plugins (*-sd.so) from the "Plugin Directory". + # + Working Directory = "@working_dir@" + SD Port = @sd_port@ + #Checkpoint Interval = 30 +} diff --git a/systemtests/tests/stresstest/etc/bareos/bconsole.conf.in b/systemtests/tests/stresstest/etc/bareos/bconsole.conf.in new file mode 100644 index 000000000..50b647c1d --- /dev/null +++ b/systemtests/tests/stresstest/etc/bareos/bconsole.conf.in @@ -0,0 +1,10 @@ +# +# Bareos User Agent (or Console) Configuration File +# + +Director { + Name = @basename@-dir + DIRport = @dir_port@ + Address = @hostname@ + Password = "@dir_password@" +} diff --git a/systemtests/tests/stresstest/test-setup b/systemtests/tests/stresstest/test-setup new file mode 100755 index 000000000..1207a7dce --- /dev/null +++ b/systemtests/tests/stresstest/test-setup @@ -0,0 +1,43 @@ +#!/bin/bash + +# BAREOS® - Backup Archiving REcovery Open Sourced +# +# Copyright (C) 2022-2022 Bareos GmbH & Co. KG +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of version three of the GNU Affero General Public +# License as published by the Free Software Foundation and included +# in the file LICENSE. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +set -e +set -o pipefail + +#shellcheck source=../environment.in +. ./environment + +#shellcheck source=../scripts/functions +. "${rscripts}"/functions +"${rscripts}"/cleanup +"${rscripts}"/setup + +if [ "$1" == "" ]; then + echo "Expecting path to data to backup." + exit -1 +fi + +echo "$1" >$tmp/file-list + +bin/bareos start + +# make sure, director is up and running. +print_debug "$(bin/bconsole <<< "status dir")" diff --git a/systemtests/tests/stresstest/testrunner-stresstest b/systemtests/tests/stresstest/testrunner-stresstest new file mode 100755 index 000000000..fcd57982d --- /dev/null +++ b/systemtests/tests/stresstest/testrunner-stresstest @@ -0,0 +1,48 @@ +#!/bin/bash +set -e +set -o pipefail +set -u +# +# Run a backup and cancel it. +# Check that metadata is still saved with checkpoints. +# +TestName="$(basename "$(pwd)")" +export TestName + +#shellcheck source=../environment.in +. ./environment + +#shellcheck source=../scripts/functions +. "${rscripts}"/functions + +backupjob=backup-bareos-fd + +backup_log=$tmp/strees-backup.out +csvlog=csvfile.csv + +rm -f $backup_log +rm -f $csvlog + +echo "runnumber,duration" >> $csvlog + +cat << END_OF_DATA >"$tmp/bconcmds" +@$out /dev/null +messages +@$out $backup_log +run job=${backupjob} level=Full yes +wait +messages +quit +END_OF_DATA + +start_test + +for i in {1..10}; do + rm -f $backup_log + run_bconsole + elapsedtime=$(grep 'Elapsed time: ' $backup_log | sed -n -e 's/^.*time: //p') + echo "$i,${elapsedtime}" >> $csvlog + rm storage/* +done + +end_test |