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