The Assimilation Project
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
jsondiscovery.c
Go to the documentation of this file.
1 
24 #include <projectcommon.h>
25 #ifdef HAVE_UNISTD_H
26 # include <unistd.h>
27 #endif
28 #include <memory.h>
29 #define DISCOVERY_SUBCLASS
30 #include <frameset.h>
31 #include <configcontext.h>
32 #include <cstringframe.h>
33 #include <frametypes.h>
34 #include <framesettypes.h>
35 #include <jsondiscovery.h>
36 #include <assert.h>
37 #include <fsprotocol.h>
43 
47 FSTATIC void _jsondiscovery_childwatch(ChildProcess*, enum HowDied, int rc, int signal, gboolean core_dumped);
48 FSTATIC void _jsondiscovery_send(JsonDiscovery* self, char * jsonout, gsize jsonlen);
51 
53 FSTATIC guint
55 {
56  const JsonDiscovery* self = CASTTOCONSTCLASS(JsonDiscovery, dself);
57  return self->_intervalsecs;
58 }
59 
61 FSTATIC void
63 {
64  JsonDiscovery* self = CASTTOCLASS(JsonDiscovery, dself);
65  if (self->jsonparams) {
66  UNREF(self->jsonparams);
67  }
68  if (self->logprefix) {
69  g_free(self->logprefix);
70  self->logprefix = NULL;
71  }
72  if (self->_fullpath) {
73  g_free(self->_fullpath);
74  self->_fullpath = NULL;
75  }
76  _discovery_finalize(dself);
77 }
78 
80 FSTATIC gboolean
82 {
83  JsonDiscovery* self = CASTTOCLASS(JsonDiscovery, dself);
84  gchar* argv[3];
85  static char discoverword [] = "discover";
86  ConfigContext* cfg = self->baseclass._config;
87  if (NULL != self->child) {
88  g_warning("%s.%d: JSON discovery process still running - skipping this iteration."
89  , __FUNCTION__, __LINE__);
90  return TRUE;
91  }
92  ++ self->baseclass.discovercount;
93  if (cfg->getaddr(cfg, CONFIGNAME_CMADISCOVER) == NULL) {
94  DEBUGMSG2("%s.%d: don't have [%s] address yet - continuing."
96  }
97  argv[0] = self->_fullpath;
98  argv[1] = discoverword;
99  argv[2] = NULL;
100 
101  DEBUGMSG1("Running Discovery [%s]", argv[0]);
102 
103  self->child = childprocess_new(0 // object size (0 == default size)
104 , argv // char** argv
105 , NULL // char** envp
106 , self->jsonparams // ConfigContext*envmod
107 , NULL // const char* curdir
109  //gboolean (*notify)(ChildProcess*, enum HowDied, int rc, int signal, gboolean core_dumped)
110 , TRUE // gboolean save_stdout
111 , G_LOG_DOMAIN // const char * logdomain
112 , self->logprefix // const char * logprefix
113 , G_LOG_LEVEL_MESSAGE // GLogLevelFlags loglevel
114 , 0 //guint32 timeout_seconds;
115 , self // gpointer user_data
117 , NULL
118  );
119  if (NULL == self->child) {
120  // Can't call childwatch w/o valid child...
121  return FALSE;
122  }
123 
124  // Don't want us going away while we have a child out there...
125  REF2(self);
126  return TRUE;
127 }
129 FSTATIC void
131 , enum HowDied status
132 , int rc
133 , int signal
134 , gboolean core_dumped)
135 {
137  gchar* jsonout = NULL;
138  gsize jsonlen = 0;
139 
140  (void)core_dumped;
141  (void)rc;
142  (void)signal;
143  if (status != EXITED_ZERO) {
144  // We don't need to log anything... It's being done for us...
145  goto quitchild;
146  }
147  jsonout = g_strdup(child->stdout_src->textread->str);
148  jsonlen = strlen(jsonout);
149  if (jsonlen == 0) {
150  g_warning("JSON discovery [%s] produced no output.", self->_fullpath);
151  goto quitchild;
152  }
153  DEBUGMSG3("Got %zd bytes of JSON TEXT: [%s]", jsonlen, jsonout);
154  if (DEBUG) {
156  if (jsobj == NULL) {
157  g_warning("JSON discovery [%s - %zd bytes] produced bad JSON."
158  , self->_fullpath, jsonlen);
159  FREE(jsonout); jsonout = NULL;
160  goto quitchild;
161  }else{
162  // Good output!
163  UNREF(jsobj);
164  }
165  }
166  _jsondiscovery_send(self, jsonout, jsonlen);
167 
168 quitchild:
169  UNREF(self->child);
170  child = NULL;
171  // We did a 'ref' in _jsondiscovery_discover above to keep us from disappearing while child was running.
172  UNREF2(self);
173 }
174 
176 FSTATIC void
177 _jsondiscovery_send(JsonDiscovery* self, char * jsonout, gsize jsonlen)
178 {
179  FrameSet* fs;
180  CstringFrame* jsf;
181  Frame* fsf;
182  ConfigContext* cfg = self->baseclass._config;
183  NetGSource* io = self->baseclass._iosource;
184  NetAddr* cma;
185  const char * basename = self->baseclass.instancename(&self->baseclass);
186 
187  g_return_if_fail(cfg != NULL && io != NULL);
188 
189  DEBUGMSG2("%s.%d: discovering %s: _sentyet == %d"
190  , __FUNCTION__, __LINE__, basename, self->baseclass._sentyet);
191  // Primitive caching - don't send what we've already sent.
192  if (self->baseclass._sentyet) {
193  const char * oldvalue = cfg->getstring(cfg, basename);
194  if (oldvalue != NULL && strcmp(jsonout, oldvalue) == 0) {
195  DEBUGMSG2("%s.%d: %s sent this value - don't send again."
196  , __FUNCTION__, __LINE__, basename);
197  g_free(jsonout);
198  return;
199  }
200  DEBUGMSG2("%s.%d: %s this value is different from previous value"
201  , __FUNCTION__, __LINE__, basename);
202  }
203  DEBUGMSG2("%s.%d: Sending %"G_GSIZE_FORMAT" bytes of JSON text"
204  , __FUNCTION__, __LINE__, jsonlen);
205  cfg->setstring(cfg, basename, jsonout);
206  cma = cfg->getaddr(cfg, CONFIGNAME_CMADISCOVER);
207  if (cma == NULL) {
208  DEBUGMSG2("%s.%d: %s address is unknown - skipping send"
209  , __FUNCTION__, __LINE__, CONFIGNAME_CMADISCOVER);
210  g_free(jsonout);
211  return;
212  }
213  self->baseclass._sentyet = TRUE;
214 
217  fsf = &jsf->baseclass; // base class object of jsf
218  fsf->setvalue(fsf, jsonout, jsonlen+1, frame_default_valuefinalize); // jsonlen is strlen(jsonout)
219  frameset_append_frame(fs, fsf);
220  DEBUGMSG2("%s.%d: Sending a %"G_GSIZE_FORMAT" bytes JSON frameset"
221  , __FUNCTION__, __LINE__, jsonlen);
222  io->_netio->sendareliablefs(io->_netio, cma, DEFAULT_FSP_QID, fs);
223  ++ self->baseclass.reportcount;
224  UNREF(fsf);
225  UNREF(fs);
226 }
227 
230 jsondiscovery_new(const char * discoverytype,
231  const char * instancename,
232  gint intervalsecs,
233  ConfigContext*jsoninst,
234  NetGSource* iosource,
235  ConfigContext*context,
236  gsize objsize)
237 {
238  const char * basedir = NULL;
239  ConfigContext* jsonparams;
240  JsonDiscovery* ret;
241  char * fullpath;
242 
244  g_return_val_if_fail(jsoninst != NULL, NULL);
245  g_return_val_if_fail(*discoverytype != '/', NULL);
246  jsonparams = jsoninst->getconfig(jsoninst, "parameters");
247  g_return_val_if_fail(jsonparams != NULL, NULL);
248  basedir = context->getstring(context, "JSONAGENTROOT");
249  if (NULL == basedir) {
250  basedir = JSONAGENTROOT;
251  }
252  fullpath = g_build_filename(basedir, discoverytype, NULL);
253  if ( !g_file_test(fullpath, G_FILE_TEST_IS_REGULAR)
254  || !g_file_test(fullpath, G_FILE_TEST_IS_EXECUTABLE)) {
255  g_warning("%s.%d: No such JSON discovery agent [%s]", __FUNCTION__, __LINE__
256  , fullpath);
257  g_free(fullpath); fullpath = NULL;
258  return NULL;
259  }
261  , discovery_new(instancename, iosource, context
262  , objsize < sizeof(JsonDiscovery) ? sizeof(JsonDiscovery) : objsize));
263  g_return_val_if_fail(ret != NULL, NULL);
264  ret->_fullpath = fullpath;
268  ret->jsonparams = jsonparams;
269  REF(ret->jsonparams);
270  ret->_intervalsecs = intervalsecs;
271  ret->logprefix = g_strdup_printf("Discovery %s: ", instancename);
272  DEBUGMSG2("%s.%d: FULLPATH=[%s] discoverytype[%s]"
273  , __FUNCTION__, __LINE__, ret->_fullpath, discoverytype);
275  return ret;
276 }