1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2000-2012 Free Software Foundation Europe e.V.
5 Copyright (C) 2011-2016 Planets Communications B.V.
6 Copyright (C) 2019-2019 Bareos GmbH & Co. KG
7
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
11 in the file LICENSE.
12
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Affero General Public License for more details.
17
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301, USA.
22 */
23
24 #include "include/bareos.h"
25 #include "cats/cats.h"
26 #include "dird/dird_conf.h"
27 #include "dird/get_database_connection.h"
28 #include "dird/job.h"
29 #include "dird/run_on_incoming_connect_interval.h"
30 #include "dird/scheduler.h"
31
32 #include <utility>
33
34 namespace directordaemon {
35
RunOnIncomingConnectInterval(std::string client_name)36 RunOnIncomingConnectInterval::RunOnIncomingConnectInterval(
37 std::string client_name)
38 : client_name_(std::move(client_name))
39 , scheduler_(Scheduler::GetMainScheduler())
40 {
41 // initialize database by job settings
42 }
43
RunOnIncomingConnectInterval(std::string client_name,Scheduler & scheduler,BareosDb * db)44 RunOnIncomingConnectInterval::RunOnIncomingConnectInterval(
45 std::string client_name,
46 Scheduler& scheduler,
47 BareosDb* db)
48 : client_name_(std::move(client_name)), scheduler_(scheduler), db_(db)
49 {
50 // constructor used for tests to inject mocked scheduler and database
51 }
52
FindLastJobStart(JobResource * job)53 time_t RunOnIncomingConnectInterval::FindLastJobStart(JobResource* job)
54 {
55 JobControlRecord* jcr = NewDirectorJcr();
56 SetJcrDefaults(jcr, job);
57 auto db = db_ != nullptr ? db_ : GetDatabaseConnection(jcr);
58 if (db == nullptr) {
59 Dmsg0(200, "Could not retrieve a database connection.");
60 return 0;
61 }
62 jcr->db = db;
63
64 std::vector<char> stime;
65
66 BareosDb::SqlFindResult result = jcr->db->FindLastJobStartTimeForJobAndClient(
67 jcr, job->resource_name_, client_name_, stime);
68
69 time_t time{-1};
70
71 switch (result) {
72 case BareosDb::SqlFindResult::kSuccess: {
73 time_t time_converted = static_cast<time_t>(StrToUtime(stime.data()));
74 time = time_converted == 0 ? -1 : time_converted;
75 break;
76 }
77 case BareosDb::SqlFindResult::kEmptyResultSet:
78 time = 0;
79 break;
80 default:
81 case BareosDb::SqlFindResult::kError:
82 time = -1;
83 break;
84 }
85
86 FreeJcr(jcr);
87
88 return time;
89 }
90
RunJobIfIntervalExceeded(JobResource * job,time_t last_start_time)91 void RunOnIncomingConnectInterval::RunJobIfIntervalExceeded(
92 JobResource* job,
93 time_t last_start_time)
94 {
95 using std::chrono::duration_cast;
96 using std::chrono::hours;
97 using std::chrono::seconds;
98 using std::chrono::system_clock;
99
100 bool interval_time_exceeded = false;
101 bool job_ran_before = last_start_time != 0;
102
103 if (job_ran_before) {
104 auto timepoint_now = system_clock::now();
105 auto timepoint_last_start = system_clock::from_time_t(last_start_time);
106
107 auto diff_seconds =
108 duration_cast<seconds>(timepoint_now - timepoint_last_start).count();
109
110 auto maximum_interval_seconds =
111 seconds(job->RunOnIncomingConnectInterval).count();
112
113 interval_time_exceeded = diff_seconds > maximum_interval_seconds;
114 }
115
116 if (!job_ran_before || interval_time_exceeded) {
117 Dmsg1(800, "Add job %s to scheduler queue.", job->resource_name_);
118 scheduler_.AddJobWithNoRunResourceToQueue(job);
119 }
120 }
121
Run()122 void RunOnIncomingConnectInterval::Run()
123 {
124 std::vector<JobResource*> job_resources =
125 GetAllJobResourcesByClientName(client_name_);
126
127 if (job_resources.empty()) { return; }
128
129 for (auto job : job_resources) {
130 if (job->RunOnIncomingConnectInterval != 0) {
131 time_t last_start_time = FindLastJobStart(job);
132 if (last_start_time != -1) {
133 Dmsg2(800, "Try RunOnIncomingConnectInterval job %s for client %s.",
134 job->resource_name_, client_name_.c_str());
135 RunJobIfIntervalExceeded(job, last_start_time);
136 }
137 }
138 }
139 }
140
141 } // namespace directordaemon
142