The Assimilation Project  based on Assimilation version 1.1.7.1474836767
resourcenagios.c
Go to the documentation of this file.
1 
23 #include <projectcommon.h>
24 #include <string.h>
25 #define RESOURCECMD_SUBCLASS
26 #include <resourcecmd.h>
27 #include <resourcenagios.h>
28 
30 
35 
38 FSTATIC void _resourcenagios_child_notify(ChildProcess*, enum HowDied, int, int, gboolean);
39 
40 FSTATIC char** _resourcenagios_create_argv(char* argv0, GSList* argv_in);
42 
43 static void (*_resourcenagios_save_finalize)(AssimObj*) = NULL;
44 
48 
51  guint structsize
52 , ConfigContext* request
53 , gpointer user_data
54 , ResourceCmdCallback callback)
55 {
56  ResourceCmd* cself;
57  ResourceNAGIOS* self;
58  const char * restype;
59  char * nagioscmd = NULL;
60  enum ConfigValType envtype;
61  enum ConfigValType argvtype;
62  GSList* incoming_argv;
63  GSList* nagiospath;
64 
66  restype = request->getstring(request, CONFIGNAME_TYPE);
67  if (NULL == restype) {
68  g_warning("%s.%d: No "CONFIGNAME_TYPE" field in NAGIOS agent request."
69  , __FUNCTION__, __LINE__);
70  return NULL;
71  }
72  if (strchr(restype, '/') != NULL) {
73  g_warning("%s.%d: "CONFIGNAME_TYPE" field in NAGIOS agent contains a slash."
74  , __FUNCTION__, __LINE__);
75  return NULL;
76  }
77 
78  envtype = request->gettype(request, REQENVIRONNAMEFIELD);
79  if (envtype != CFG_EEXIST && envtype != CFG_CFGCTX) {
80  g_warning("%s.%d: "REQENVIRONNAMEFIELD" field in NAGIOS request is invalid."
81  , __FUNCTION__, __LINE__);
82  return NULL;
83  }
84 
85  argvtype = request->gettype(request, REQARGVNAMEFIELD);
86  if (argvtype != CFG_EEXIST && argvtype != CFG_ARRAY) {
87  g_warning("%s.%d: "REQARGVNAMEFIELD" field in NAGIOS request is invalid (not an array)."
88  , __FUNCTION__, __LINE__);
89  return NULL;
90  }
91 
92  nagiospath = request->getarray(request, REQNAGIOSPATH);
93  if (NULL == nagiospath) {
94  g_warning("%s.%d: "REQNAGIOSPATH" field in NAGIOS request is missing."
95  , __FUNCTION__, __LINE__);
96  return NULL;
97  }
98 
99  // Search for the the requested agent in the given path (REQNAGIOSPATH)
100  for (;nagiospath; nagiospath = g_slist_next(nagiospath)) {
101  ConfigValue* thisval;
102  thisval = CASTTOCLASS(ConfigValue, nagiospath->data);
103  if (thisval->valtype != CFG_STRING) {
104  g_warning("%s.%d: Malformed "REQNAGIOSPATH" in NAGIOS request."
105  , __FUNCTION__, __LINE__);
106  return NULL;
107  }
108  nagioscmd = g_build_filename(thisval->u.strvalue, restype, NULL);
109  if ( !g_file_test(nagioscmd, G_FILE_TEST_IS_REGULAR)
110  || !g_file_test(nagioscmd, G_FILE_TEST_IS_EXECUTABLE)) {
111  g_free(nagioscmd); nagioscmd = NULL;
112  }else{
113  break;
114  }
115  }
116  if (NULL == nagioscmd) {
117  g_warning("%s.%d: No such NAGIOS agent: %s"
118  , __FUNCTION__, __LINE__, restype);
119  return NULL;
120  }
121 
122  incoming_argv = request->getarray(request, REQARGVNAMEFIELD);
123 
124  if (structsize < sizeof(ResourceNAGIOS)) {
125  structsize = sizeof(ResourceNAGIOS);
126  }
127  cself = resourcecmd_constructor(structsize, request, user_data, callback);
128  if (NULL == cself) {
129  return NULL;
130  }
131  if (!_resourcenagios_save_finalize) {
132  _resourcenagios_save_finalize = cself->baseclass._finalize;
133  }
136  self = NEWSUBCLASS(ResourceNAGIOS, cself);
137  self->nagioscmd = nagioscmd;
138  self->environment = configcontext_new(0);
139  self->baseclass.loggingname = g_strdup_printf("%s:%s: "
140  , self->baseclass.resourcename, self->baseclass.operation);
141  self->argv = _resourcenagios_create_argv(self->nagioscmd, incoming_argv);
143  self->child = NULL;
144  return cself;
145 }
146 
148 FSTATIC char **
150  GSList* argv_in)
151 {
152  int incoming_count = g_slist_length(argv_in);
153  int argc;
154  char** result;
155 
156  // Needs to be +2, not +1 as noted above
157  result = (char **) MALLOC((incoming_count+2)*sizeof(char *));
158 
159  // Make our return result (argument list)
160  result[0] = g_strdup(argv0);
161  for (argc=1; argc <= incoming_count && argv_in; ++argc, argv_in = g_slist_next(argv_in)) {
162  ConfigValue* elem = CASTTOCLASS(ConfigValue, argv_in->data);
163  char * nextval;
164  switch (elem->valtype) {
165  case CFG_STRING:
166  nextval = g_strdup(elem->u.strvalue);
167  break;
168  case CFG_NETADDR: {
169  NetAddr* addr = elem->u.addrvalue;
170  nextval = addr->baseclass.toString(&addr->baseclass);
171  }
172  break;
173  default:
174  nextval = configcontext_elem_toString(elem);
175  break;
176  }
177  result[argc] = nextval;
178  }
179  result[argc] = NULL;
180  if (DEBUG >= 3) {
181  int j;
182  g_warning("%s.%d: Dumping %d Arguments for %s:", __FUNCTION__, __LINE__
183  , argc+1, argv0);
184  for (j=0; result[argc]; ++j) {
185  g_warning("%s.%d: arg[%d] = %s", __FUNCTION__, __LINE__, j, result[j]);
186  }
187  }
188  return result;
189 }
190 
191 // Initialize all the NAGIOS environment variables
192 FSTATIC void
194 {
195  ConfigContext* p = self->baseclass.request->getconfig(self->baseclass.request
197  GSList* names;
198  GSList* thisname;
199 
200  names = p ? p->keys(p) : NULL;
201 
202  // If there are no parameters given, that 'names' *will* be NULL!
203  // That's how an empty list comes out in a GSList...
204  for(thisname = names; NULL != thisname; thisname=thisname->next) {
205  const char * mapname;
206  const char * value;
207  if (NULL == thisname->data) {
208  continue;
209  }
210  mapname = (const char*)thisname->data;
211  value = p->getstring(p, (char*)thisname->data);
212 
213  if (NULL == value) {
214  // Ignore non-string values
215  continue;
216  }
217  self->environment->setstring(self->environment, mapname, value);
218  }
219  if (NULL != names) {
220  g_slist_free(names);
221  names = NULL;
222  }
223 
224  // Last but not least!
225  self->environment->setstring(self->environment, "NAGIOS_RESOURCE_INSTANCE"
226  , self->baseclass.resourcename);
227 }
228 
230 void
232 {
233  ResourceNAGIOS* self = CASTTOCLASS(ResourceNAGIOS, aself);
234 
235  DEBUGMSG2("Finalizing ResourceNAGIOS @ %p: %s", self, self->baseclass.loggingname);
236  if (self->nagioscmd) {
237  g_free(self->nagioscmd);
238  self->nagioscmd = NULL;
239  }
240  if (self->child) {
241  DEBUGMSG5("%s.%d: UNREF child: (self=%p %s)", __FUNCTION__,__LINE__
242  , self->child, self->baseclass.loggingname);
243  UNREF(self->child);
244  }else{
245  DEBUGMSG("%s.%d: NO CHILD TO UNREF (self=%p %s)", __FUNCTION__,__LINE__,self
246  , self->baseclass.loggingname);
247  }
248  if (self->environment) {
249  UNREF(self->environment);
250  }
251  if (self->argv) {
252  char ** thisarg;
253  for (thisarg = self->argv; *thisarg; ++thisarg) {
254  g_free(*thisarg);
255  }
256  g_free(self->argv);
257  self->argv = NULL;
258  }
259  _resourcenagios_save_finalize(aself);
260 }
261 
263 FSTATIC void
265 {
266  ResourceNAGIOS* self = CASTTOCLASS(ResourceNAGIOS, cmdself);
267  enum ChildErrLogMode logmode;
268  gboolean save_stdout;
269 
270  DEBUGMSG3("%s.%d Executing(%s:%s)", __FUNCTION__, __LINE__
271  , self->baseclass.resourcename, self->baseclass.operation);
272  if (self->baseclass.is_running) {
273  g_warning("%s.%d: %s:%s is currently running. New request ignored."
274  , __FUNCTION__, __LINE__
275  , self->baseclass.resourcename, self->baseclass.operation);
276  return;
277  }
278  if (self->child) {
279  // Oh... A repeating operation
280  DEBUGMSG3("UNREFing previous child at %p", self->child);
281  UNREF(self->child);
282  }
283  logmode = (self->baseclass.callback ? CHILD_NOLOG : CHILD_LOGALL);
284 
285  /* save_stdout = _resourcenagios_outputs_string(self->baseclass.operation); */
286  save_stdout = TRUE;
287  self->baseclass.starttime = g_get_monotonic_time();
288 
289  self->child = childprocess_new
290  ( 0
291  , self->argv
292  , NULL
293  , self->environment
294  , NULL
297  , save_stdout
298  , NULL
299  , self->baseclass.loggingname
300  , G_LOG_LEVEL_INFO
301  , self->baseclass.timeout_secs
302  , self
303  , logmode
304  , self->baseclass.loggingname
305  );
306  if (self->child) {
307  self->baseclass.is_running = TRUE;
308  REF2(self); // We can't go away while we're running no matter what...
309  // (this is undone after calling our callback function).
310  DEBUGMSG5("%s.%d: REF resourcenagios: %p", __FUNCTION__,__LINE__,self);
311  DEBUGMSG("%s.%d: spawned child: %p", __FUNCTION__,__LINE__,self->child);
312  }else{
313  DEBUGMSG("%s.%d FAILED execution(%s:%s)", __FUNCTION__, __LINE__
314  , self->baseclass.resourcename, self->baseclass.operation);
315  }
316 }
317 
320 FSTATIC void
322 , enum HowDied exittype
323 , int rc
324 , int signal
325 , gboolean core_dumped)
326 {
328  char * outread = NULL;
329 
330  self->baseclass.endtime = g_get_monotonic_time();
331  if (self->child->stdout_src->textread
332  && self->child->stdout_src->textread->str) {
333  outread = self->child->stdout_src->textread->str;
334  }else{
335  outread = NULL;
336  }
337 
338  if (outread && exittype != EXITED_ZERO
339  && strcmp(self->baseclass.operation, MONITOROP) == 0) {
340  g_warning("%s: %s", self->baseclass.loggingname, outread);
341  }
344 
345  DEBUGMSG2("%s.%d: Exit happened exittype:%d", __FUNCTION__, __LINE__, exittype);
346  if (self->baseclass.callback) {
347  DEBUGMSG2("%s.%d: Calling callback - exittype:%d", __FUNCTION__,__LINE__,exittype);
348  self->baseclass.callback(self->baseclass.request
349  , self->baseclass.user_data
350  , exittype
351  , rc
352  , signal
353  , core_dumped
354  , outread);
355  }
356 
357  self->baseclass.is_running = FALSE;
358  DEBUGMSG5("%s.%d: UNREF resourcenagios: %p", __FUNCTION__,__LINE__,self);
359  UNREF2(self); // Undo the ref we did before executing
360 }
void(* ResourceCmdCallback)(ConfigContext *request, gpointer user_data, enum HowDied reason, int rc, int signal, gboolean core_dumped, const char *stringresult)
Definition: resourcecmd.h:44
Log all exits - normal or abnormal.
Definition: childprocess.h:49
enum ConfigValType valtype
Definition: configcontext.h:59
ResourceCmd * resourcenagios_new(guint structsize, ConfigContext *request, gpointer user_data, ResourceCmdCallback callback)
Constructor for ResourceNAGIOS class.
#define REF2(obj)
Definition: assimobj.h:40
#define CONFIGNAME_TYPE
Type of resource or discovery.
GSList *(* getarray)(const ConfigContext *, const char *name)
Get array value.
Definition: configcontext.h:84
WINEXPORT ChildProcess * childprocess_new(gsize cpsize, char **argv, const char **envp, ConfigContext *envmod, const char *curdir, void(*notify)(ChildProcess *, enum HowDied, int rc, int signal, gboolean core_dumped), gboolean save_stdout, const char *logdomain, const char *logprefix, GLogLevelFlags loglevel, guint32 timeout_seconds, gpointer user_data, enum ChildErrLogMode logmode, const char *logname)
ChildProcess class. constructor.
Definition: childprocess.c:85
char * strvalue
Definition: configcontext.h:64
#define DEBUGMSG(...)
Definition: proj_classes.h:87
#define DEBUGMSG5(...)
Definition: proj_classes.h:93
AssimObj baseclass
Definition: netaddr.h:44
const char *(* getstring)(const ConfigContext *, const char *name)
Get String value.
Definition: configcontext.h:86
Implements the NAGIOS resource class.
void(* execute)(ResourceCmd *self)
Execute this resource command.
Definition: resourcecmd.h:58
#define REQARGVNAMEFIELD
Definition: resourcecmd.h:81
#define FSTATIC
Definition: projectcommon.h:31
#define DEBUGMSG3(...)
Definition: proj_classes.h:91
gpointer user_data
User data given to us when the object was created.
Definition: childprocess.h:69
int signal
Definition: childprocess.c:238
FSTATIC char ** _resourcenagios_create_argv(char *argv0, GSList *argv_in)
Create command line arguments for our child process.
ResourceCmd * resourcecmd_constructor(guint structsize, ConfigContext *request, gpointer user_data, ResourceCmdCallback callback)
Constructor (_new function) for ResourceCmd "abstract" class.
Definition: resourcecmd.c:113
#define BINDDEBUG(Cclass)
BINDDEBUG is for telling the class system where the debug variable for this class is - put it in the ...
Definition: proj_classes.h:82
union _ConfigValue::@2 u
AssimObj baseclass
Definition: configcontext.h:72
#define __FUNCTION__
#define DEBUG
Definition: proj_classes.h:85
FSTATIC void _resourcenagios_finalize(AssimObj *aself)
Finalize function for ResourceNAGIOS objects.
WINEXPORT char * configcontext_elem_toString(ConfigValue *val)
Convert a ConfigContext element (ConfigValue) to a String.
WINEXPORT gint64 g_get_monotonic_time(void)
Local replacement for g_get_monotonic_time() - for old releases of glib.
gchar *(* toString)(gconstpointer)
Produce malloc-ed string representation.
Definition: assimobj.h:58
Project common header file.
FSTATIC void _resourcenagios_execute(ResourceCmd *self)
Do the deed, dude!
Don&#39;t log anything when it quits.
Definition: childprocess.h:46
AssimObj baseclass
Base object: implements ref, unref, toString.
Definition: resourcecmd.h:51
#define MONITOROP
Definition: resourcecmd.h:83
ConfigValType
Definition: configcontext.h:44
struct _ResourceNAGIOS ResourceNAGIOS
NetAddr * addrvalue
Definition: configcontext.h:66
FSTATIC void _resourcenagios_child_notify(ChildProcess *, enum HowDied, int, int, gboolean)
We get called when our child exits, times out and is killed, or times out and can&#39;t be killed...
The NetAddr class class represents a general network address - whether IP, MAC, or any other type of ...
Definition: netaddr.h:43
HowDied
Definition: childprocess.h:35
#define MALLOC(nbytes)
should it just call g_malloc?
Definition: projectcommon.h:26
#define REQENVIRONNAMEFIELD
Definition: resourcecmd.h:72
#define REQNAGIOSPATH
enum ConfigValType(* gettype)(const ConfigContext *, const char *)
Return type.
Definition: configcontext.h:99
Exited with zero return code.
Definition: childprocess.h:37
ChildErrLogMode
Definition: childprocess.h:45
#define DEBUGDECLARATIONS
Definition: proj_classes.h:79
GSList *(* keys)(const ConfigContext *)
Return list of keys.
Implements the resource command abstract class.
#define DEBUGMSG2(...)
Definition: proj_classes.h:90
ConfigContext * configcontext_new(gsize objsize)
Construct a new ConfigContext object - with no values defaulted.
void(* _finalize)(AssimObj *)
Free object (private)
Definition: assimobj.h:55
#define UNREF2(obj)
Definition: assimobj.h:36
FSTATIC void _resourcenagios_init_environ(ResourceNAGIOS *self)
#define CASTTOCLASS(Cclass, obj)
Safely cast &#39;obj&#39; to C-class &#39;class&#39; - verifying that it was registerd as being of type class ...
Definition: proj_classes.h:66
#define UNREF(obj)
Definition: assimobj.h:35
#define NEWSUBCLASS(Cclass, obj)
Definition: proj_classes.h:67