1 /*
2  * Copyright 2004-2018 Andrew Beekhof <andrew@beekhof.net>
3  *
4  * This source code is licensed under the GNU Lesser General Public License
5  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
6  */
7 
8 #include <crm_internal.h>
9 
10 #ifndef _GNU_SOURCE
11 #  define _GNU_SOURCE
12 #endif
13 
14 #include <stdio.h>
15 #include <string.h>
16 #include <stdlib.h>
17 #include <ctype.h>
18 
19 #include <crm/crm.h>
20 #include <crm/lrmd.h>
21 #include <crm/msg_xml.h>
22 #include <crm/common/xml.h>
23 #include <crm/common/util.h>
24 
25 /*!
26  * \brief Generate an operation key
27  *
28  * \param[in] rsc_id    ID of resource being operated on
29  * \param[in] op_type   Operation name
30  * \param[in] interval  Operation interval
31  *
32  * \return Newly allocated memory containing operation key as string
33  *
34  * \note It is the caller's responsibility to free() the result.
35  */
36 char *
generate_op_key(const char * rsc_id,const char * op_type,int interval)37 generate_op_key(const char *rsc_id, const char *op_type, int interval)
38 {
39     CRM_ASSERT(rsc_id != NULL);
40     CRM_ASSERT(op_type != NULL);
41     CRM_ASSERT(interval >= 0);
42     return crm_strdup_printf("%s_%s_%d", rsc_id, op_type, interval);
43 }
44 
45 gboolean
parse_op_key(const char * key,char ** rsc_id,char ** op_type,int * interval)46 parse_op_key(const char *key, char **rsc_id, char **op_type, int *interval)
47 {
48     char *notify = NULL;
49     char *mutable_key = NULL;
50     char *mutable_key_ptr = NULL;
51     int len = 0, offset = 0, ch = 0;
52     int local_interval_ms = 0;
53 
54     // Initialize output variables in case of early return
55     if (rsc_id) {
56         *rsc_id = NULL;
57     }
58     if (op_type) {
59         *op_type = NULL;
60     }
61     if (interval) {
62         *interval = 0;
63     }
64 
65     CRM_CHECK(key && *key, return FALSE);
66 
67     // Parse interval at end of string
68     len = strlen(key);
69     offset = len - 1;
70 
71     crm_trace("Source: %s", key);
72 
73     while (offset > 0 && isdigit(key[offset])) {
74         int digits = len - offset;
75 
76         ch = key[offset] - '0';
77         CRM_CHECK(ch < 10, return FALSE);
78         CRM_CHECK(ch >= 0, return FALSE);
79         while (digits > 1) {
80             digits--;
81             ch = ch * 10;
82         }
83         local_interval_ms += ch;
84         offset--;
85     }
86     crm_trace("Operation key '%s' has interval %ums", key, local_interval_ms);
87     if (interval) {
88         *interval = local_interval_ms;
89     }
90 
91     CRM_CHECK((offset != (len - 1)) && (key[offset] == '_'), return FALSE);
92 
93     mutable_key = strndup(key, offset);
94     offset--;
95 
96     while (offset > 0 && key[offset] != '_') {
97         offset--;
98     }
99 
100     CRM_CHECK(key[offset] == '_',
101               free(mutable_key); return FALSE);
102 
103     mutable_key_ptr = mutable_key + offset + 1;
104 
105     crm_trace("  Action: %s", mutable_key_ptr);
106     if (op_type) {
107         *op_type = strdup(mutable_key_ptr);
108     }
109 
110     mutable_key[offset] = 0;
111     offset--;
112 
113     notify = strstr(mutable_key, "_post_notify");
114     if (notify && safe_str_eq(notify, "_post_notify")) {
115         notify[0] = 0;
116     }
117 
118     notify = strstr(mutable_key, "_pre_notify");
119     if (notify && safe_str_eq(notify, "_pre_notify")) {
120         notify[0] = 0;
121     }
122 
123     crm_trace("  Resource: %s", mutable_key);
124     if (rsc_id) {
125         *rsc_id = mutable_key;
126     } else {
127         free(mutable_key);
128     }
129 
130     return TRUE;
131 }
132 
133 char *
generate_notify_key(const char * rsc_id,const char * notify_type,const char * op_type)134 generate_notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
135 {
136     int len = 12;
137     char *op_id = NULL;
138 
139     CRM_CHECK(rsc_id != NULL, return NULL);
140     CRM_CHECK(op_type != NULL, return NULL);
141     CRM_CHECK(notify_type != NULL, return NULL);
142 
143     len += strlen(op_type);
144     len += strlen(rsc_id);
145     len += strlen(notify_type);
146     if(len > 0) {
147         op_id = malloc(len);
148     }
149     if (op_id != NULL) {
150         sprintf(op_id, "%s_%s_notify_%s_0", rsc_id, notify_type, op_type);
151     }
152     return op_id;
153 }
154 
155 char *
generate_transition_magic_v202(const char * transition_key,int op_status)156 generate_transition_magic_v202(const char *transition_key, int op_status)
157 {
158     int len = 80;
159     char *fail_state = NULL;
160 
161     CRM_CHECK(transition_key != NULL, return NULL);
162 
163     len += strlen(transition_key);
164 
165     fail_state = malloc(len);
166     if (fail_state != NULL) {
167         snprintf(fail_state, len, "%d:%s", op_status, transition_key);
168     }
169     return fail_state;
170 }
171 
172 char *
generate_transition_magic(const char * transition_key,int op_status,int op_rc)173 generate_transition_magic(const char *transition_key, int op_status, int op_rc)
174 {
175     int len = 80;
176     char *fail_state = NULL;
177 
178     CRM_CHECK(transition_key != NULL, return NULL);
179 
180     len += strlen(transition_key);
181 
182     fail_state = malloc(len);
183     if (fail_state != NULL) {
184         snprintf(fail_state, len, "%d:%d;%s", op_status, op_rc, transition_key);
185     }
186     return fail_state;
187 }
188 
189 gboolean
decode_transition_magic(const char * magic,char ** uuid,int * transition_id,int * action_id,int * op_status,int * op_rc,int * target_rc)190 decode_transition_magic(const char *magic, char **uuid, int *transition_id, int *action_id,
191                         int *op_status, int *op_rc, int *target_rc)
192 {
193     int res = 0;
194     char *key = NULL;
195     gboolean result = TRUE;
196 
197     CRM_CHECK(magic != NULL, return FALSE);
198     CRM_CHECK(op_rc != NULL, return FALSE);
199     CRM_CHECK(op_status != NULL, return FALSE);
200 
201     key = calloc(1, strlen(magic) + 1);
202     res = sscanf(magic, "%d:%d;%s", op_status, op_rc, key);
203     if (res != 3) {
204         crm_warn("Only found %d items in: '%s'", res, magic);
205         free(key);
206         return FALSE;
207     }
208 
209     CRM_CHECK(decode_transition_key(key, uuid, transition_id, action_id, target_rc), result = FALSE);
210 
211     free(key);
212     return result;
213 }
214 
215 char *
generate_transition_key(int transition_id,int action_id,int target_rc,const char * node)216 generate_transition_key(int transition_id, int action_id, int target_rc, const char *node)
217 {
218     int len = 40;
219     char *fail_state = NULL;
220 
221     CRM_CHECK(node != NULL, return NULL);
222 
223     len += strlen(node);
224 
225     fail_state = malloc(len);
226     if (fail_state != NULL) {
227         snprintf(fail_state, len, "%d:%d:%d:%-*s", action_id, transition_id, target_rc, 36, node);
228     }
229     return fail_state;
230 }
231 
232 gboolean
decode_transition_key(const char * key,char ** uuid,int * transition_id,int * action_id,int * target_rc)233 decode_transition_key(const char *key, char **uuid, int *transition_id, int *action_id,
234                       int *target_rc)
235 {
236     int res = 0;
237     gboolean done = FALSE;
238 
239     CRM_CHECK(uuid != NULL, return FALSE);
240     CRM_CHECK(target_rc != NULL, return FALSE);
241     CRM_CHECK(action_id != NULL, return FALSE);
242     CRM_CHECK(transition_id != NULL, return FALSE);
243 
244     *uuid = calloc(1, 37);
245     res = sscanf(key, "%d:%d:%d:%36s", action_id, transition_id, target_rc, *uuid);
246     switch (res) {
247         case 4:
248             /* Post Pacemaker 0.6 */
249             done = TRUE;
250             break;
251         case 3:
252         case 2:
253             /* this can be tricky - the UUID might start with an integer */
254 
255             /* Until Pacemaker 0.6 */
256             done = TRUE;
257             *target_rc = -1;
258             res = sscanf(key, "%d:%d:%36s", action_id, transition_id, *uuid);
259             if (res == 2) {
260                 *action_id = -1;
261                 res = sscanf(key, "%d:%36s", transition_id, *uuid);
262                 CRM_CHECK(res == 2, done = FALSE);
263 
264             } else if (res != 3) {
265                 CRM_CHECK(res == 3, done = FALSE);
266             }
267             break;
268 
269         case 1:
270             /* Prior to Heartbeat 2.0.8 */
271             done = TRUE;
272             *action_id = -1;
273             *target_rc = -1;
274             res = sscanf(key, "%d:%36s", transition_id, *uuid);
275             CRM_CHECK(res == 2, done = FALSE);
276             break;
277         default:
278             crm_crit("Unhandled sscanf result (%d) for %s", res, key);
279     }
280 
281     if (strlen(*uuid) != 36) {
282         crm_warn("Bad UUID (%s) in sscanf result (%d) for %s", *uuid, res, key);
283     }
284 
285     if (done == FALSE) {
286         crm_err("Cannot decode '%s' rc=%d", key, res);
287 
288         free(*uuid);
289         *uuid = NULL;
290         *target_rc = -1;
291         *action_id = -1;
292         *transition_id = -1;
293     }
294 
295     return done;
296 }
297 
298 void
filter_action_parameters(xmlNode * param_set,const char * version)299 filter_action_parameters(xmlNode * param_set, const char *version)
300 {
301     char *key = NULL;
302     char *timeout = NULL;
303     char *interval = NULL;
304 
305     const char *attr_filter[] = {
306         XML_ATTR_ID,
307         XML_ATTR_CRM_VERSION,
308         XML_LRM_ATTR_OP_DIGEST,
309         XML_LRM_ATTR_TARGET,
310         XML_LRM_ATTR_TARGET_UUID,
311         "pcmk_external_ip"
312     };
313 
314     gboolean do_delete = FALSE;
315     int lpc = 0;
316     static int meta_len = 0;
317 
318     if (meta_len == 0) {
319         meta_len = strlen(CRM_META);
320     }
321 
322     if (param_set == NULL) {
323         return;
324     }
325 
326     for (lpc = 0; lpc < DIMOF(attr_filter); lpc++) {
327         xml_remove_prop(param_set, attr_filter[lpc]);
328     }
329 
330     key = crm_meta_name(XML_LRM_ATTR_INTERVAL);
331     interval = crm_element_value_copy(param_set, key);
332     free(key);
333 
334     key = crm_meta_name(XML_ATTR_TIMEOUT);
335     timeout = crm_element_value_copy(param_set, key);
336 
337     if (param_set) {
338         xmlAttrPtr xIter = param_set->properties;
339 
340         while (xIter) {
341             const char *prop_name = (const char *)xIter->name;
342 
343             xIter = xIter->next;
344             do_delete = FALSE;
345             if (strncasecmp(prop_name, CRM_META, meta_len) == 0) {
346                 do_delete = TRUE;
347             }
348 
349             if (do_delete) {
350                 xml_remove_prop(param_set, prop_name);
351             }
352         }
353     }
354 
355     if (crm_get_msec(interval) > 0 && compare_version(version, "1.0.8") > 0) {
356         /* Re-instate the operation's timeout value */
357         if (timeout != NULL) {
358             crm_xml_add(param_set, key, timeout);
359         }
360     }
361 
362     free(interval);
363     free(timeout);
364     free(key);
365 }
366 
367 #define FAKE_TE_ID	"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
368 static void
append_digest(lrmd_event_data_t * op,xmlNode * update,const char * version,const char * magic,int level)369 append_digest(lrmd_event_data_t * op, xmlNode * update, const char *version, const char *magic,
370               int level)
371 {
372     /* this will enable us to later determine that the
373      *   resource's parameters have changed and we should force
374      *   a restart
375      */
376     char *digest = NULL;
377     xmlNode *args_xml = NULL;
378 
379     if (op->params == NULL) {
380         return;
381     }
382 
383     args_xml = create_xml_node(NULL, XML_TAG_PARAMS);
384     g_hash_table_foreach(op->params, hash2field, args_xml);
385     filter_action_parameters(args_xml, version);
386     digest = calculate_operation_digest(args_xml, version);
387 
388 #if 0
389     if (level < get_crm_log_level()
390         && op->interval == 0 && crm_str_eq(op->op_type, CRMD_ACTION_START, TRUE)) {
391         char *digest_source = dump_xml_unformatted(args_xml);
392 
393         do_crm_log(level, "Calculated digest %s for %s (%s). Source: %s\n",
394                    digest, ID(update), magic, digest_source);
395         free(digest_source);
396     }
397 #endif
398     crm_xml_add(update, XML_LRM_ATTR_OP_DIGEST, digest);
399 
400     free_xml(args_xml);
401     free(digest);
402 }
403 
404 int
rsc_op_expected_rc(lrmd_event_data_t * op)405 rsc_op_expected_rc(lrmd_event_data_t * op)
406 {
407     int rc = 0;
408 
409     if (op && op->user_data) {
410         int dummy = 0;
411         char *uuid = NULL;
412 
413         decode_transition_key(op->user_data, &uuid, &dummy, &dummy, &rc);
414         free(uuid);
415     }
416     return rc;
417 }
418 
419 gboolean
did_rsc_op_fail(lrmd_event_data_t * op,int target_rc)420 did_rsc_op_fail(lrmd_event_data_t * op, int target_rc)
421 {
422     switch (op->op_status) {
423         case PCMK_LRM_OP_CANCELLED:
424         case PCMK_LRM_OP_PENDING:
425             return FALSE;
426             break;
427 
428         case PCMK_LRM_OP_NOTSUPPORTED:
429         case PCMK_LRM_OP_TIMEOUT:
430         case PCMK_LRM_OP_ERROR:
431             return TRUE;
432             break;
433 
434         default:
435             if (target_rc != op->rc) {
436                 return TRUE;
437             }
438     }
439 
440     return FALSE;
441 }
442 
443 /*!
444  * \brief Create a CIB XML element for an operation
445  *
446  * \param[in] parent    If not NULL, make new XML node a child of this one
447  * \param[in] prefix    Generate an ID using this prefix
448  * \param[in] task      Operation task to set
449  * \param[in] interval  Operation interval to set
450  * \param[in] timeout   If not NULL, operation timeout to set
451  *
452  * \return New XML object on success, NULL otherwise
453  */
454 xmlNode *
crm_create_op_xml(xmlNode * parent,const char * prefix,const char * task,const char * interval,const char * timeout)455 crm_create_op_xml(xmlNode *parent, const char *prefix, const char *task,
456                   const char *interval, const char *timeout)
457 {
458     xmlNode *xml_op;
459 
460     CRM_CHECK(prefix && task && interval, return NULL);
461 
462     xml_op = create_xml_node(parent, XML_ATTR_OP);
463     crm_xml_set_id(xml_op, "%s-%s-%s", prefix, task, interval);
464     crm_xml_add(xml_op, XML_LRM_ATTR_INTERVAL, interval);
465     crm_xml_add(xml_op, "name", task);
466     if (timeout) {
467         crm_xml_add(xml_op, XML_ATTR_TIMEOUT, timeout);
468     }
469     return xml_op;
470 }
471 
472 xmlNode *
create_operation_update(xmlNode * parent,lrmd_event_data_t * op,const char * caller_version,int target_rc,const char * node,const char * origin,int level)473 create_operation_update(xmlNode * parent, lrmd_event_data_t * op, const char * caller_version,
474                         int target_rc, const char * node, const char * origin, int level)
475 {
476     char *key = NULL;
477     char *magic = NULL;
478     char *op_id = NULL;
479     char *op_id_additional = NULL;
480     char *local_user_data = NULL;
481     const char *exit_reason = NULL;
482 
483     xmlNode *xml_op = NULL;
484     const char *task = NULL;
485     gboolean dc_munges_migrate_ops = (compare_version(caller_version, "3.0.3") < 0);
486     gboolean dc_needs_unique_ops = (compare_version(caller_version, "3.0.6") < 0);
487 
488     CRM_CHECK(op != NULL, return NULL);
489     do_crm_log(level, "%s: Updating resource %s after %s op %s (interval=%d)",
490                origin, op->rsc_id, op->op_type, services_lrm_status_str(op->op_status),
491                op->interval);
492 
493     crm_trace("DC version: %s", caller_version);
494 
495     task = op->op_type;
496     /* remap the task name under various scenarios
497      * this makes life easier for the PE when trying determine the current state
498      */
499     if (crm_str_eq(task, "reload", TRUE)) {
500         if (op->op_status == PCMK_LRM_OP_DONE) {
501             task = CRMD_ACTION_START;
502         } else {
503             task = CRMD_ACTION_STATUS;
504         }
505 
506     } else if (dc_munges_migrate_ops && crm_str_eq(task, CRMD_ACTION_MIGRATE, TRUE)) {
507         /* if the migrate_from fails it will have enough info to do the right thing */
508         if (op->op_status == PCMK_LRM_OP_DONE) {
509             task = CRMD_ACTION_STOP;
510         } else {
511             task = CRMD_ACTION_STATUS;
512         }
513 
514     } else if (dc_munges_migrate_ops
515                && op->op_status == PCMK_LRM_OP_DONE
516                && crm_str_eq(task, CRMD_ACTION_MIGRATED, TRUE)) {
517         task = CRMD_ACTION_START;
518     }
519 
520     key = generate_op_key(op->rsc_id, task, op->interval);
521     if (dc_needs_unique_ops && op->interval > 0) {
522         op_id = strdup(key);
523 
524     } else if (crm_str_eq(task, CRMD_ACTION_NOTIFY, TRUE)) {
525         const char *n_type = crm_meta_value(op->params, "notify_type");
526         const char *n_task = crm_meta_value(op->params, "notify_operation");
527 
528         CRM_LOG_ASSERT(n_type != NULL);
529         CRM_LOG_ASSERT(n_task != NULL);
530         op_id = generate_notify_key(op->rsc_id, n_type, n_task);
531 
532         if (op->op_status != PCMK_LRM_OP_PENDING) {
533             /* Ignore notify errors.
534              *
535              * @TODO It might be better to keep the correct result here, and
536              * ignore it in process_graph_event().
537              */
538             op->op_status = PCMK_LRM_OP_DONE;
539             op->rc = 0;
540         }
541 
542     } else if (did_rsc_op_fail(op, target_rc)) {
543         op_id = generate_op_key(op->rsc_id, "last_failure", 0);
544         if (op->interval == 0) {
545             /* Ensure 'last' gets updated too in case recording-pending="true" */
546             op_id_additional = generate_op_key(op->rsc_id, "last", 0);
547         }
548         exit_reason = op->exit_reason;
549 
550     } else if (op->interval > 0) {
551         op_id = strdup(key);
552 
553     } else {
554         op_id = generate_op_key(op->rsc_id, "last", 0);
555     }
556 
557   again:
558     xml_op = find_entity(parent, XML_LRM_TAG_RSC_OP, op_id);
559     if (xml_op == NULL) {
560         xml_op = create_xml_node(parent, XML_LRM_TAG_RSC_OP);
561     }
562 
563     if (op->user_data == NULL) {
564         crm_debug("Generating fake transition key for:"
565                   " %s_%s_%d %d from %s",
566                   op->rsc_id, op->op_type, op->interval, op->call_id, origin);
567         local_user_data = generate_transition_key(-1, op->call_id, target_rc, FAKE_TE_ID);
568         op->user_data = local_user_data;
569     }
570 
571     if(magic == NULL) {
572         magic = generate_transition_magic(op->user_data, op->op_status, op->rc);
573     }
574 
575     crm_xml_add(xml_op, XML_ATTR_ID, op_id);
576     crm_xml_add(xml_op, XML_LRM_ATTR_TASK_KEY, key);
577     crm_xml_add(xml_op, XML_LRM_ATTR_TASK, task);
578     crm_xml_add(xml_op, XML_ATTR_ORIGIN, origin);
579     crm_xml_add(xml_op, XML_ATTR_CRM_VERSION, caller_version);
580     crm_xml_add(xml_op, XML_ATTR_TRANSITION_KEY, op->user_data);
581     crm_xml_add(xml_op, XML_ATTR_TRANSITION_MAGIC, magic);
582     crm_xml_add(xml_op, XML_LRM_ATTR_EXIT_REASON, exit_reason == NULL ? "" : exit_reason);
583     crm_xml_add(xml_op, XML_LRM_ATTR_TARGET, node); /* For context during triage */
584 
585     crm_xml_add_int(xml_op, XML_LRM_ATTR_CALLID, op->call_id);
586     crm_xml_add_int(xml_op, XML_LRM_ATTR_RC, op->rc);
587     crm_xml_add_int(xml_op, XML_LRM_ATTR_OPSTATUS, op->op_status);
588     crm_xml_add_int(xml_op, XML_LRM_ATTR_INTERVAL, op->interval);
589 
590     if (compare_version("2.1", caller_version) <= 0) {
591         if (op->t_run || op->t_rcchange || op->exec_time || op->queue_time) {
592             crm_trace("Timing data (%s_%s_%d): last=%u change=%u exec=%u queue=%u",
593                       op->rsc_id, op->op_type, op->interval,
594                       op->t_run, op->t_rcchange, op->exec_time, op->queue_time);
595 
596             if (op->interval == 0) {
597                 /* The values are the same for non-recurring ops */
598                 crm_xml_add_int(xml_op, XML_RSC_OP_LAST_RUN, op->t_run);
599                 crm_xml_add_int(xml_op, XML_RSC_OP_LAST_CHANGE, op->t_run);
600 
601             } else if(op->t_rcchange) {
602                 /* last-run is not accurate for recurring ops */
603                 crm_xml_add_int(xml_op, XML_RSC_OP_LAST_CHANGE, op->t_rcchange);
604 
605             } else {
606                 /* ...but is better than nothing otherwise */
607                 crm_xml_add_int(xml_op, XML_RSC_OP_LAST_CHANGE, op->t_run);
608             }
609 
610             crm_xml_add_int(xml_op, XML_RSC_OP_T_EXEC, op->exec_time);
611             crm_xml_add_int(xml_op, XML_RSC_OP_T_QUEUE, op->queue_time);
612         }
613     }
614 
615     if (crm_str_eq(op->op_type, CRMD_ACTION_MIGRATE, TRUE)
616         || crm_str_eq(op->op_type, CRMD_ACTION_MIGRATED, TRUE)) {
617         /*
618          * Record migrate_source and migrate_target always for migrate ops.
619          */
620         const char *name = XML_LRM_ATTR_MIGRATE_SOURCE;
621 
622         crm_xml_add(xml_op, name, crm_meta_value(op->params, name));
623 
624         name = XML_LRM_ATTR_MIGRATE_TARGET;
625         crm_xml_add(xml_op, name, crm_meta_value(op->params, name));
626     }
627 
628     append_digest(op, xml_op, caller_version, magic, LOG_DEBUG);
629 
630     if (op_id_additional) {
631         free(op_id);
632         op_id = op_id_additional;
633         op_id_additional = NULL;
634         goto again;
635     }
636 
637     if (local_user_data) {
638         free(local_user_data);
639         op->user_data = NULL;
640     }
641     free(magic);
642     free(op_id);
643     free(key);
644     return xml_op;
645 }
646 
647 /*!
648  * \brief Check whether an operation requires resource agent meta-data
649  *
650  * \param[in] rsc_class  Resource agent class (or NULL to skip class check)
651  * \param[in] op         Operation action (or NULL to skip op check)
652  *
653  * \return TRUE if operation needs meta-data, FALSE otherwise
654  * \note At least one of rsc_class and op must be specified.
655  */
656 bool
crm_op_needs_metadata(const char * rsc_class,const char * op)657 crm_op_needs_metadata(const char *rsc_class, const char *op)
658 {
659     /* Agent meta-data is used to determine whether a reload is possible, and to
660      * evaluate versioned parameters -- so if this op is not relevant to those
661      * features, we don't need the meta-data.
662      */
663 
664     CRM_CHECK(rsc_class || op, return FALSE);
665 
666     if (rsc_class
667         && is_not_set(pcmk_get_ra_caps(rsc_class), pcmk_ra_cap_params)) {
668         /* Meta-data is only needed for resource classes that use parameters */
669         return FALSE;
670     }
671 
672     /* Meta-data is only needed for these actions */
673     if (op
674         && strcmp(op, CRMD_ACTION_START)
675         && strcmp(op, CRMD_ACTION_STATUS)
676         && strcmp(op, CRMD_ACTION_PROMOTE)
677         && strcmp(op, CRMD_ACTION_DEMOTE)
678         && strcmp(op, CRMD_ACTION_RELOAD)
679         && strcmp(op, CRMD_ACTION_MIGRATE)
680         && strcmp(op, CRMD_ACTION_MIGRATED)
681         && strcmp(op, CRMD_ACTION_NOTIFY)) {
682         return FALSE;
683     }
684 
685     return TRUE;
686 }
687