The Assimilation Project  based on Assimilation version 1.1.7.1474836767
resourceocf.c
Go to the documentation of this file.
1 
22 #include <projectcommon.h>
23 #include <string.h>
24 #define RESOURCECMD_SUBCLASS
25 #include <resourcecmd.h>
26 #include <resourceocf.h>
27 
29 
34 
37 FSTATIC void _resourceocf_child_notify(ChildProcess*, enum HowDied, int, int, gboolean);
38 FSTATIC gboolean _resourceocf_outputs_string(const char * operation);
39 
41 
42 static void (*_resourceocf_save_finalize)(AssimObj*) = NULL;
43 
47 
50  guint structsize
51 , ConfigContext* request
52 , gpointer user_data
53 , ResourceCmdCallback callback)
54 {
55  ResourceCmd* cself;
56  ResourceOCF* self;
57  const char * restype;
58  char * ocfpath;
59  const char * provider;
60  enum ConfigValType envtype;
61 
63  restype = request->getstring(request, CONFIGNAME_TYPE);
64  if (NULL == restype) {
65  g_warning("%s.%d: No "CONFIGNAME_TYPE" field in OCF agent request."
66  , __FUNCTION__, __LINE__);
67  return NULL;
68  }
69  if (strchr(restype, '/') != NULL) {
70  g_warning("%s.%d: "CONFIGNAME_TYPE" field in OCF agent contains a slash."
71  , __FUNCTION__, __LINE__);
72  return NULL;
73  }
74  provider = request->getstring(request, REQPROVIDERNAMEFIELD);
75  if (NULL == provider) {
76  g_warning("%s.%d: No "REQPROVIDERNAMEFIELD" field in OCF agent request."
77  , __FUNCTION__, __LINE__);
78  return NULL;
79  }
80  if (strchr(provider, '/') != NULL) {
81  g_warning("%s.%d: "REQPROVIDERNAMEFIELD" field in OCF agent contains a slash."
82  , __FUNCTION__, __LINE__);
83  return NULL;
84  }
85 
86  envtype = request->gettype(request, REQENVIRONNAMEFIELD);
87  if (envtype != CFG_EEXIST && envtype != CFG_CFGCTX) {
88  g_warning("%s.%d: "REQENVIRONNAMEFIELD" field in OCF request is invalid."
89  , __FUNCTION__, __LINE__);
90  return NULL;
91  }
92 
93  ocfpath = g_build_filename(OCF_ROOT, OCF_RES_D, provider, restype, NULL);
94  if ( !g_file_test(ocfpath, G_FILE_TEST_IS_REGULAR)
95  || !g_file_test(ocfpath, G_FILE_TEST_IS_EXECUTABLE)) {
96  g_warning("%s.%d: No OCF Resource agent [%s]", __FUNCTION__, __LINE__
97  , ocfpath);
98  g_free(ocfpath); ocfpath = NULL;
99  return NULL;
100  }
101 
102  if (structsize < sizeof(ResourceOCF)) {
103  structsize = sizeof(ResourceOCF);
104  }
105  cself = resourcecmd_constructor(structsize, request, user_data, callback);
106  if (NULL == cself) {
107  return NULL;
108  }
109  if (!_resourceocf_save_finalize) {
110  _resourceocf_save_finalize = cself->baseclass._finalize;
111  }
113  cself->execute = _resourceocf_execute;
114  self = NEWSUBCLASS(ResourceOCF, cself);
115  self->ocfpath = ocfpath;
116  self->environment = configcontext_new(0);
117  self->baseclass.loggingname = g_strdup_printf("%s:%s: "
118  , self->baseclass.resourcename, self->baseclass.operation);
119  self->argv[0] = g_strdup(self->ocfpath);
120  self->argv[1] = g_strdup(self->baseclass.operation);
121  self->argv[2] = 0;
122  self->child = NULL;
124  return cself;
125 }
126 // Initialize all the OCF environment variables
127 FSTATIC void
129 {
130  ConfigContext* p = self->baseclass.request->getconfig(self->baseclass.request
132  GSList* names;
133  GSList* thisname;
134 
135  if (NULL == p) {
136  g_warning("%s.%d: No proper "REQENVIRONNAMEFIELD" field in request"
137  , __FUNCTION__, __LINE__);
138  return;
139  }
140  // If there are no parameters given, that 'names' *will* be NULL!
141  // That's how an empty list comes out in a GSList...
142  names = p->keys(p);
143 
144 
145  for(thisname = names; NULL != thisname; thisname=thisname->next) {
146  char * mapname;
147  const char * value;
148  if (NULL == thisname->data) {
149  continue;
150  }
151  mapname = g_strdup_printf("OCF_RESKEY_%s", (char*)thisname->data);
152  value = p->getstring(p, (char*)thisname->data);
153 
154  if (NULL == value) {
155  // Ignore non-string values
156  g_free(mapname); mapname = NULL;
157  continue;
158  }
159  self->environment->setstring(self->environment, mapname, value);
160  g_free(mapname); mapname = NULL;
161  }
162  if (NULL != names) {
163  g_slist_free(names);
164  names = NULL;
165  }
166 
167  // Last but not least!
168  self->environment->setstring(self->environment, "OCF_ROOT", OCF_ROOT);
169  self->environment->setstring(self->environment, "OCF_RESOURCE_INSTANCE"
170  , self->baseclass.resourcename);
171  // Unofficial but often needed value
172  self->environment->setstring(self->environment, "HA_RSCTMP", HB_RSCTMPDIR);
173 }
174 
176 void
178 {
179  ResourceOCF* self = CASTTOCLASS(ResourceOCF, aself);
180  guint j;
181 
182  DEBUGMSG2("Finalizing ResourceOCF @ %p: %s", self, self->baseclass.loggingname);
183  if (self->ocfpath) {
184  g_free(self->ocfpath);
185  self->ocfpath = NULL;
186  }
187  for (j=0; j < 3; ++j) {
188  g_free(self->argv[j]);
189  self->argv[j] = NULL;
190  }
191  if (self->child) {
192  DEBUGMSG5("%s.%d: UNREF child: (self=%p %s)", __FUNCTION__,__LINE__
193  , self->child, self->baseclass.loggingname);
194  UNREF(self->child);
195  }else{
196  DEBUGMSG("%s.%d: NO CHILD TO UNREF (self=%p %s)", __FUNCTION__,__LINE__,self
197  , self->baseclass.loggingname);
198  }
199  if (self->baseclass.loggingname) {
200  g_free(self->baseclass.loggingname);
201  self->baseclass.loggingname = NULL;
202  }
203  if (self->environment) {
204  UNREF(self->environment);
205  }
206  _resourceocf_save_finalize(aself);
207 }
208 
209 // Return TRUE if this operation type returns a string
210 FSTATIC gboolean
211 _resourceocf_outputs_string(const char * operation)
212 {
213  guint j;
214  const char * oplist[] = {
215  MONITOROP,
216  METADATAOP
217  };
218 
219  for (j=0; j < DIMOF(oplist); ++j) {
220  if (strcmp(operation, oplist[j]) == 0) {
221  return TRUE;
222  }
223  }
224  return FALSE;
225 }
226 
228 FSTATIC void
230 {
231  ResourceOCF* self = CASTTOCLASS(ResourceOCF, cmdself);
232  enum ChildErrLogMode logmode;
233  gboolean save_stdout;
234 
235  DEBUGMSG3("%s.%d Executing(%s:%s)", __FUNCTION__, __LINE__
236  , self->baseclass.resourcename, self->baseclass.operation);
237  if (self->baseclass.is_running) {
238  g_warning("%s.%d: %s:%s is currently running. New request ignored."
239  , __FUNCTION__, __LINE__
240  , self->baseclass.resourcename, self->baseclass.operation);
241  return;
242  }
243  if (self->child) {
244  // Oh... A repeating operation
245  UNREF(self->child);
246  }
247  logmode = (self->baseclass.callback ? CHILD_NOLOG : CHILD_LOGALL);
248 
249  save_stdout = _resourceocf_outputs_string(self->baseclass.operation);
250  self->baseclass.starttime = g_get_monotonic_time();
251 
252  self->child = childprocess_new
253  ( 0
254  , self->argv
255  , NULL
256  , self->environment
257  , NULL
260  , save_stdout
261  , NULL
262  , self->baseclass.loggingname
263  , G_LOG_LEVEL_INFO
264  , self->baseclass.timeout_secs
265  , self
266  , logmode
267  , self->baseclass.loggingname
268  );
269  if (self->child) {
270  self->baseclass.is_running = TRUE;
271  REF2(self); // We can't go away while we're running no matter what...
272  // (this is undone after calling our callback function).
273  DEBUGMSG5("%s.%d: REF resourceocf: %p", __FUNCTION__,__LINE__,self);
274  DEBUGMSG("%s.%d: spawned child: %p", __FUNCTION__,__LINE__,self->child);
275  }else{
276  DEBUGMSG("%s.%d FAILED execution(%s:%s)", __FUNCTION__, __LINE__
277  , self->baseclass.resourcename, self->baseclass.operation);
278  }
279 }
280 
283 FSTATIC void
285 , enum HowDied exittype
286 , int rc
287 , int signal
288 , gboolean core_dumped)
289 {
290  ResourceOCF* self = CASTTOCLASS(ResourceOCF, child->user_data);
291  char * outread = NULL;
292 
293  self->baseclass.endtime = g_get_monotonic_time();
294  if (self->child->stdout_src->textread
295  && self->child->stdout_src->textread->str) {
296  outread = self->child->stdout_src->textread->str;
297  }else{
298  outread = NULL;
299  }
300 
301  if (outread && exittype != EXITED_ZERO
302  && strcmp(self->baseclass.operation, MONITOROP) == 0) {
303  g_warning("%s: %s", self->baseclass.loggingname, outread);
304  }
305 
306  DEBUGMSG2("%s.%d: Exit happened exittype:%d", __FUNCTION__, __LINE__, exittype);
307  if (self->baseclass.callback) {
308  DEBUGMSG2("%s.%d: Calling callback - exittype:%d", __FUNCTION__,__LINE__,exittype);
309  self->baseclass.callback(self->baseclass.request
310  , self->baseclass.user_data
311  , exittype
312  , rc
313  , signal
314  , core_dumped
315  , outread);
316  }
317 
318  self->baseclass.is_running = FALSE;
319  DEBUGMSG5("%s.%d: UNREF resourceocf: %p", __FUNCTION__,__LINE__,self);
320  UNREF2(self); // Undo the ref we did before executing
321 }
FSTATIC void _resourceocf_finalize(AssimObj *aself)
Finalize function for ResourceOCF objects.
Definition: resourceocf.c:177
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
#define OCF_RES_D
Definition: resourceocf.h:53
FSTATIC void _resourceocf_init_environ(ResourceOCF *self)
Definition: resourceocf.c:128
#define REQPROVIDERNAMEFIELD
Definition: resourcecmd.h:70
#define REF2(obj)
Definition: assimobj.h:40
#define CONFIGNAME_TYPE
Type of resource or discovery.
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
#define DEBUGMSG(...)
Definition: proj_classes.h:87
#define DEBUGMSG5(...)
Definition: proj_classes.h:93
const char *(* getstring)(const ConfigContext *, const char *name)
Get String value.
Definition: configcontext.h:86
ResourceCmd * resourceocf_new(guint structsize, ConfigContext *request, gpointer user_data, ResourceCmdCallback callback)
Constructor for ResourceOCF class.
Definition: resourceocf.c:49
void(* execute)(ResourceCmd *self)
Execute this resource command.
Definition: resourcecmd.h:58
#define FSTATIC
Definition: projectcommon.h:31
#define DEBUGMSG3(...)
Definition: proj_classes.h:91
FSTATIC gboolean _resourceocf_outputs_string(const char *operation)
Definition: resourceocf.c:211
gpointer user_data
User data given to us when the object was created.
Definition: childprocess.h:69
int signal
Definition: childprocess.c:238
ResourceCmd * resourcecmd_constructor(guint structsize, ConfigContext *request, gpointer user_data, ResourceCmdCallback callback)
Constructor (_new function) for ResourceCmd "abstract" class.
Definition: resourcecmd.c:113
#define HB_RSCTMPDIR
Definition: resourceocf.h:54
#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
AssimObj baseclass
Definition: configcontext.h:72
#define __FUNCTION__
#define OCF_ROOT
Definition: resourceocf.h:52
WINEXPORT gint64 g_get_monotonic_time(void)
Local replacement for g_get_monotonic_time() - for old releases of glib.
#define METADATAOP
Definition: resourcecmd.h:84
Implements the OCF resource class.
Project common header file.
#define DIMOF(a)
Definition: lldp_min.c:30
Don&#39;t log anything when it quits.
Definition: childprocess.h:46
AssimObj baseclass
Base object: implements ref, unref, toString.
Definition: resourcecmd.h:51
struct _ResourceOCF ResourceOCF
Definition: resourceocf.h:42
#define MONITOROP
Definition: resourcecmd.h:83
ConfigValType
Definition: configcontext.h:44
HowDied
Definition: childprocess.h:35
#define REQENVIRONNAMEFIELD
Definition: resourcecmd.h:72
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
#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
FSTATIC void _resourceocf_execute(ResourceCmd *self)
Do the deed, dude!
Definition: resourceocf.c:229
FSTATIC void _resourceocf_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...
Definition: resourceocf.c:284
#define NEWSUBCLASS(Cclass, obj)
Definition: proj_classes.h:67