FOSSology  3.2.0rc1
Open Source License Compliance by Open Source Software
libfossscheduler.c
Go to the documentation of this file.
1 /***************************************************************
2 Copyright (C) 2010-2011 Hewlett-Packard Development Company, L.P.
3 Copyright (C) 2015 Siemens AG
4 
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 version 2 as published by the Free Software Foundation.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 
18 ***************************************************************/
19 
25 /* local includes */
26 #include "libfossscheduler.h"
27 #include "libfossdb.h"
28 #include "fossconfig.h"
29 
30 /* unix includes */
31 #include <stdio.h>
32 #include <getopt.h>
33 #include <libgen.h>
34 #include <glib.h>
35 
36 /* ************************************************************************** */
37 /* **** Locals ************************************************************** */
38 /* ************************************************************************** */
39 
40 volatile gint items_processed;
41 volatile int alive;
42 char buffer[2048];
43 int valid;
45 int userID;
46 int groupID;
47 int jobId;
48 char* module_name = NULL;
49 
51 const static char* sql_check = "\
52  SELECT * FROM agent \
53  WHERE agent_name = '%s' AND agent_rev='%s.%s'";
54 
56 const static char* sql_insert = "\
57  INSERT INTO agent (agent_name, agent_rev, agent_desc) \
58  VALUES ('%s', '%s.%s', '%s')";
59 
63 char* sysconfigdir = NULL;
64 
65 /* these will be freed in fo_scheduler_disconnect */
66 extern GRegex* fo_conf_parse;
67 extern GRegex* fo_conf_replace;
68 
77 
88 {
89  int processed = g_atomic_int_get(&items_processed);
90  // TODO these functions are not safe for a signal handler
91  fprintf(stdout, "HEART: %d %d\n", processed, alive);
92  fflush(stdout);
93  fflush(stderr);
94  alarm(ALARM_SECS);
95  alive = FALSE;
96 }
97 
106 {
107  PGresult* db_result = NULL;
108  char* db_sql = NULL;
109 
110  db_sql = g_strdup_printf(sql_check, module_name,
111  fo_config_get(sysconfig, module_name, "VERSION", NULL),
112  fo_config_get(sysconfig, module_name, "COMMIT_HASH", NULL));
113  db_result = PQexec(db_conn, db_sql);
114  if (PQresultStatus(db_result) != PGRES_TUPLES_OK)
115  {
116  fprintf(stderr, "FATAL %s.%d: unable to check agent table: %s",
117  __FILE__, __LINE__, PQresultErrorMessage(db_result));
118  fflush(stderr);
119  PQfinish(db_conn);
120  PQclear(db_result);
121  g_free(db_sql);
122  exit(252);
123  }
124 
125  if (PQntuples(db_result) != 1)
126  {
127  g_free(db_sql);
128  PQclear(db_result);
129 
130  db_sql = g_strdup_printf(sql_insert, module_name,
131  fo_config_get(sysconfig, module_name, "VERSION", NULL),
132  fo_config_get(sysconfig, module_name, "COMMIT_HASH", NULL),
133  fo_config_get(sysconfig, module_name, "DESCRIPTION", NULL));
134  db_result = PQexec(db_conn, db_sql);
135  if (PQresultStatus(db_result) != PGRES_COMMAND_OK)
136  {
137  fprintf(stderr, "FATAL %s.%d: unable to insert into agent table: %s",
138  __FILE__, __LINE__, PQresultErrorMessage(db_result));
139  fflush(stderr);
140  PQfinish(db_conn);
141  PQclear(db_result);
142  g_free(db_sql);
143  exit(251);
144  }
145  }
146 
147  g_free(db_sql);
148  PQclear(db_result);
149 }
150 
151 /* ************************************************************************** */
152 /* **** Global Functions **************************************************** */
153 /* ************************************************************************** */
154 
165 {
166  g_atomic_int_add(&items_processed, i);
167  alive = TRUE;
168 
169  fflush(stdout);
170  fflush(stderr);
171 }
172 
181 void fo_scheduler_connect_conf(int* argc, char** argv, PGconn** db_conn, char** db_conf)
182 {
183  /* locals */
184  GError* error = NULL;
185  GOptionContext* parsed;
186  fo_conf* version;
187  char fname[FILENAME_MAX + 1];
188 
189  char* db_config = NULL;
190  char* db_error = NULL;
191 
192  /* command line options */
193  GOptionEntry options[] =
194  {
195  {"config", 'c', 0, G_OPTION_ARG_STRING, &sysconfigdir, ""},
196  {"userID", 0, 0, G_OPTION_ARG_INT, &userID, ""},
197  {"groupID", 0, 0, G_OPTION_ARG_INT, &groupID, ""},
198  {"scheduler_start", 0, 0, G_OPTION_ARG_NONE, &sscheduler, ""},
199  {"jobId", 0, 0, G_OPTION_ARG_INT, &jobId, ""},
200  {NULL}
201  };
202 
203  /* initialize memory associated with agent connection */
204  module_name = g_strdup(basename(argv[0]));
205  sysconfigdir = DEFAULT_SETUP;
206  items_processed = 0;
207  valid = 0;
208  sscheduler = 0;
209  userID = -1;
210  groupID = -1;
211  agent_verbose = 0;
212  memset(buffer, 0, sizeof(buffer));
213 
214  if (sysconfig != NULL)
215  {
216  LOG_WARNING("fo_scheduler_connect() has already been called.");
217  sscheduler = 1;
218  return;
219  }
220 
221  if (getenv("FO_SYSCONFDIR"))
222  sysconfigdir = getenv("FO_SYSCONFDIR");
223 
224  /* parse command line options */
225  parsed = g_option_context_new("");
226  g_option_context_add_main_entries(parsed, options, NULL);
227  g_option_context_set_ignore_unknown_options(parsed, TRUE);
228  g_option_context_set_help_enabled(parsed, FALSE);
229  g_option_context_parse(parsed, argc, &argv, NULL);
230  g_option_context_free(parsed);
231 
232  /* load system configuration */
233  if (sysconfigdir)
234  {
235  snprintf(fname, FILENAME_MAX, "%s/%s", sysconfigdir, "fossology.conf");
236  sysconfig = fo_config_load(fname, &error);
237  if (error)
238  {
239  fprintf(stderr, "FATAL %s.%d: unable to open system configuration: %s\n",
240  __FILE__, __LINE__, error->message);
241  exit(255);
242  }
243 
244  snprintf(fname, FILENAME_MAX, "%s/mods-enabled/%s/VERSION",
246 
247  version = fo_config_load(fname, &error);
248  if (error)
249  {
250  fprintf(stderr, "FATAL %s.%d: unable to open VERSION configuration: %s\n",
251  __FILE__, __LINE__, error->message);
252  exit(254);
253  }
254 
255  fo_config_join(sysconfig, version, &error);
256  if (error)
257  {
258  fprintf(stderr, "FATAL %s.%d: unable to join configuration files: %s\n",
259  __FILE__, __LINE__, error->message);
260  exit(250);
261  }
262 
263 
264  fo_config_free(version);
265  }
266 
267  /* create the database connection */
268  if (db_conn)
269  {
270  db_config = g_strdup_printf("%s/Db.conf", sysconfigdir);
271  (*db_conn) = fo_dbconnect(db_config, &db_error);
272  if (db_conf)
273  *db_conf = db_config;
274  else
275  g_free(db_config);
276  if (db_error)
277  {
278  fprintf(stderr, "FATAL %s.%d: unable to open database connection: %s\n",
279  __FILE__, __LINE__, db_error);
280  fflush(stderr);
281  exit(253);
282  }
283  }
284 
285  /* send "OK" to the scheduler */
286  if (sscheduler)
287  {
288  /* check that the agent record exists */
289  if (db_conn)
290  fo_check_agentdb(*db_conn);
291 
292  if (fo_config_has_key(sysconfig, module_name, "VERSION"))
293  fprintf(stdout, "VERSION: %s\n",
294  fo_config_get(sysconfig, module_name, "VERSION", &error));
295  else fprintf(stdout, "VERSION: unknown\n");
296  fprintf(stdout, "\nOK\n");
297  fflush(stdout);
298 
299  /* set up the heartbeat() */
300  signal(SIGALRM, fo_heartbeat);
301  alarm(ALARM_SECS);
302  }
303 
304  fflush(stdout);
305  fflush(stderr);
306 
307  alive = TRUE;
308 }
309 
331 void fo_scheduler_connect(int* argc, char** argv, PGconn** db_conn)
332 {
333  fo_scheduler_connect_conf(argc, argv, db_conn, NULL);
334 }
335 
341 void fo_scheduler_connect_dbMan(int* argc, char** argv, fo_dbManager** dbManager)
342 {
343  char* dbConf;
344  PGconn* dbConnection;
345  fo_scheduler_connect_conf(argc, argv, &dbConnection, &dbConf);
346  *dbManager = fo_dbManager_new_withConf(dbConnection, dbConf);
347  free(dbConf);
348 }
349 
358 void fo_scheduler_disconnect(int retcode)
359 {
360  if (module_name != NULL) {
361  /* send "CLOSED" to the scheduler */
362  if (sscheduler)
363  {
364  fo_heartbeat();
365  fprintf(stdout, "\nBYE %d\n", retcode);
366  fflush(stdout);
367 
368  valid = 0;
369  sscheduler = 0;
370 
371  g_free(module_name);
372  }
373 
374  if (strcmp(sysconfigdir, DEFAULT_SETUP))
375  g_free(sysconfigdir);
376 
377  fo_config_free(sysconfig);
378  }
379  g_regex_unref(fo_conf_parse);
380  g_regex_unref(fo_conf_replace);
381 
382  sysconfigdir = NULL;
383  sysconfig = NULL;
384  fo_conf_parse = NULL;
385  fo_conf_replace = NULL;
386  module_name = NULL;
387 
388  fflush(stdout);
389  fflush(stderr);
390 }
391 
413 {
414  fflush(stdout);
415 
416  /* get the next line from the scheduler and possibly WAIT */
417  while (fgets(buffer, sizeof(buffer), stdin) != NULL)
418  {
419  if (agent_verbose)
420  printf("\nNOTE: received %s\n", buffer);
421  if (strncmp(buffer, "CLOSE", 5) == 0)
422  break;
423  if (strncmp(buffer, "END", 3) == 0)
424  {
425  fprintf(stdout, "\nOK\n");
426  fflush(stdout);
427  fflush(stderr);
428  valid = 0;
429  continue;
430  }
431  else if (strncmp(buffer, "VERBOSE", 7) == 0)
432  {
433  agent_verbose = atoi(&buffer[8]);
434  valid = 0;
435  continue;
436  }
437  else if (strncmp(buffer, "VERSION", 7) == 0)
438  {
439  if (fo_config_has_key(sysconfig, module_name, "VERSION"))
440  fprintf(stdout, "VERSION: %s\n",
441  fo_config_get(sysconfig, module_name, "VERSION", NULL));
442  else fprintf(stdout, "VERSION: unknown\n");
443  fflush(stdout);
444  fflush(stderr);
445  valid = 0;
446  continue;
447  }
448 
449  buffer[strlen(buffer) - 1] = '\0';
450  valid = 1;
451  return buffer;
452  }
453 
454  valid = 0;
455 
456  fflush(stdout);
457  fflush(stderr);
458 
459  return NULL;
460 }
461 
471 {
472  return valid ? buffer : NULL;
473 }
474 
484 void fo_scheduler_set_special(int option, int value)
485 {
486  fprintf(stdout, "SPECIAL: %d %d\n", option, value);
487  fflush(stdout);
488 }
489 
503 {
504  int value;
505 
506  fprintf(stdout, "GETSPECIAL: %d\n", option);
507  fflush(stdout);
508 
509  if (fscanf(stdin, "VALUE: %d\n", &value) != 1)
510  return 0;
511  return value;
512 }
513 
520 {
521  return jobId;
522 }
523 
530 {
531  return userID;
532 }
533 
540 {
541  return groupID;
542 }
543 
554 char* fo_sysconfig(const char* sectionname, const char* variablename)
555 {
556  GError* error = NULL;
557  char* ret;
558 
559  ret = fo_config_get(
560  sysconfig,
561  sectionname,
562  variablename,
563  &error);
564 
565  fflush(stdout);
566  fflush(stderr);
567 
568  if (error)
569  {
570  g_clear_error(&error);
571  ret = NULL;
572  }
573 
574  return ret;
575 }
void fo_config_join(fo_conf *dst, fo_conf *src, GError **error)
Takes all groups and key from a fo_conf and adds them to another.
Definition: fossconfig.c:536
volatile int alive
If the agent has updated with a hearbeat.
FOSSology library to read config file.
void fo_heartbeat()
Internal function to send a heartbeat to the scheduler along with the number of items processed...
fo_conf * sysconfig
const ALARM_SECS
Definition: Agent.php:43
int fo_scheduler_groupID()
Gets the id of the group that created the job that the agent is running.
int userID
The id of the user that created the job.
int valid
If the information stored in buffer is valid.
char * fo_scheduler_current()
Get the last read string from the scheduler.
void fo_scheduler_connect_conf(int *argc, char **argv, PGconn **db_conn, char **db_conf)
Establish a connection between an agent and the scheduler.
int jobId
The id of the job.
void fo_scheduler_disconnect(int retcode)
Disconnect the scheduler connection.
void fo_scheduler_connect(int *argc, char **argv, PGconn **db_conn)
Establish a connection between an agent and the scheduler.
int sscheduler
Whether the agent was started by the scheduler.
char * fo_config_get(fo_conf *conf, const char *group, const char *key, GError **error)
Gets an element based on its group name and key name. If the group or key is not found, the error object is set and NULL is returned.
Definition: fossconfig.c:341
static const char * sql_insert
volatile gint items_processed
The number of items processed by the agent.
void fo_scheduler_set_special(int option, int value)
Sets something special about the agent within the scheduler.
int agent_verbose
Common verbose flags for the agents, this is used so that the scheduler can change the verbose level ...
int fo_config_has_key(fo_conf *conf, char *group, char *key)
Checks if the a specific group in the currently parsed configuration file has a specific key...
Definition: fossconfig.c:673
char * sysconfigdir
GRegex * fo_conf_parse
Regex for parsing.
Definition: fossconfig.c:69
GRegex * fo_conf_replace
Regex for replace.
Definition: fossconfig.c:70
int fo_scheduler_get_special(int option)
Gets if a particular special attribute is set in the scheduler.
int fo_scheduler_userID()
Gets the id of the user that created the job that the agent is running.
static const char * sql_check
int groupID
The id of the group of the user that created the job.
char buffer[2048]
The last thing received from the scheduler.
fo_dbManager * dbManager
fo_dbManager object
Definition: process.c:28
void fo_scheduler_connect_dbMan(int *argc, char **argv, fo_dbManager **dbManager)
Make a connection from an agent to the scheduler and create a DB manager as well. ...
int fo_scheduler_jobId()
Gets the id of the job that the agent is running.
char * module_name
The name of the agent.
void fo_config_free(fo_conf *conf)
Frees the memory associated with the internal configuration data structures.
Definition: fossconfig.c:511
PGconn * db_conn
The connection to Database.
Definition: pkgagent.c:34
char * fo_scheduler_next()
Get the next data to process from the scheduler.
void fo_scheduler_heart(int i)
This function must be called by agents to let the scheduler know they are alive and how many items th...
fo_conf * fo_config_load(char *rawname, GError **error)
Load the configuration information from the provided file.
Definition: fossconfig.c:280
void fo_check_agentdb(PGconn *db_conn)
Checks that the agent is already in the agent table.
FUNCTION int processed(PGconn *pgConn, int agent_pk, int nomos_agent_pk, int pfile_pk, int uploadtree_pk, int bucketpool_pk, int bucket_pk)
Has this pfile or uploadtree_pk already been bucket processed? This only works if the bucket has been...
Definition: validate.c:150
char * fo_sysconfig(const char *sectionname, const char *variablename)
gets a system configuration variable from the configuration data.
PGconn * fo_dbconnect(char *DBConfFile, char **ErrorBuf)
Connect to a database. The default is Db.conf.
Definition: libfossdb.c:40