This source file includes following definitions.
- pcmk__op_key
- convert_interval
- try_fast_match
- try_basic_match
- try_migrate_notify_match
- parse_op_key
- pcmk__notify_key
- decode_transition_magic
- pcmk__transition_key
- decode_transition_key
- pcmk__filter_op_for_digest
- rsc_op_expected_rc
- did_rsc_op_fail
- crm_create_op_xml
- crm_op_needs_metadata
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #ifndef _GNU_SOURCE
13 # define _GNU_SOURCE
14 #endif
15
16 #include <regex.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include <sys/types.h>
21 #include <ctype.h>
22
23 #include <crm/crm.h>
24 #include <crm/lrmd.h>
25 #include <crm/msg_xml.h>
26 #include <crm/common/xml.h>
27 #include <crm/common/util.h>
28
29 static regex_t *notify_migrate_re = NULL;
30
31
32
33
34
35
36
37
38
39
40
41
42
43 char *
44 pcmk__op_key(const char *rsc_id, const char *op_type, guint interval_ms)
45 {
46 CRM_ASSERT(rsc_id != NULL);
47 CRM_ASSERT(op_type != NULL);
48 return crm_strdup_printf(PCMK__OP_FMT, rsc_id, op_type, interval_ms);
49 }
50
51 static inline gboolean
52 convert_interval(const char *s, guint *interval_ms)
53 {
54 unsigned long l;
55
56 errno = 0;
57 l = strtoul(s, NULL, 10);
58
59 if (errno != 0) {
60 return FALSE;
61 }
62
63 *interval_ms = (guint) l;
64 return TRUE;
65 }
66
67 static gboolean
68 try_fast_match(const char *key, const char *underbar1, const char *underbar2,
69 char **rsc_id, char **op_type, guint *interval_ms)
70 {
71 if (interval_ms) {
72 if (!convert_interval(underbar2+1, interval_ms)) {
73 return FALSE;
74 }
75 }
76
77 if (rsc_id) {
78 *rsc_id = strndup(key, underbar1-key);
79 }
80
81 if (op_type) {
82 *op_type = strndup(underbar1+1, underbar2-underbar1-1);
83 }
84
85 return TRUE;
86 }
87
88 static gboolean
89 try_basic_match(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
90 {
91 char *interval_sep = NULL;
92 char *type_sep = NULL;
93
94
95 interval_sep = strrchr(key, '_');
96 if (interval_sep == NULL) {
97 return FALSE;
98 }
99
100 if (interval_ms) {
101 if (!convert_interval(interval_sep+1, interval_ms)) {
102 return FALSE;
103 }
104 }
105
106 type_sep = interval_sep-1;
107
108 while (1) {
109 if (*type_sep == '_') {
110 break;
111 } else if (type_sep == key) {
112 if (interval_ms) {
113 *interval_ms = 0;
114 }
115
116 return FALSE;
117 }
118
119 type_sep--;
120 }
121
122 if (op_type) {
123
124
125 *op_type = strndup(type_sep+1, interval_sep-type_sep-1);
126 }
127
128
129 if (rsc_id) {
130 *rsc_id = strndup(key, type_sep-key);
131 }
132
133 return TRUE;
134 }
135
136 static gboolean
137 try_migrate_notify_match(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
138 {
139 int rc = 0;
140 size_t nmatch = 8;
141 regmatch_t pmatch[nmatch];
142
143 if (notify_migrate_re == NULL) {
144
145 notify_migrate_re = calloc(1, sizeof(regex_t));
146 rc = regcomp(notify_migrate_re, "^(.*)_(migrate_(from|to)|(pre|post)_notify_([a-z]+|migrate_(from|to)))_([0-9]+)$",
147 REG_EXTENDED);
148 CRM_ASSERT(rc == 0);
149 }
150
151 rc = regexec(notify_migrate_re, key, nmatch, pmatch, 0);
152 if (rc == REG_NOMATCH) {
153 return FALSE;
154 }
155
156 if (rsc_id) {
157 *rsc_id = strndup(key+pmatch[1].rm_so, pmatch[1].rm_eo-pmatch[1].rm_so);
158 }
159
160 if (op_type) {
161 *op_type = strndup(key+pmatch[2].rm_so, pmatch[2].rm_eo-pmatch[2].rm_so);
162 }
163
164 if (interval_ms) {
165 if (!convert_interval(key+pmatch[7].rm_so, interval_ms)) {
166 if (rsc_id) {
167 free(*rsc_id);
168 *rsc_id = NULL;
169 }
170
171 if (op_type) {
172 free(*op_type);
173 *op_type = NULL;
174 }
175
176 return FALSE;
177 }
178 }
179
180 return TRUE;
181 }
182
183 gboolean
184 parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
185 {
186 char *underbar1 = NULL;
187 char *underbar2 = NULL;
188 char *underbar3 = NULL;
189
190
191 if (rsc_id) {
192 *rsc_id = NULL;
193 }
194
195 if (op_type) {
196 *op_type = NULL;
197 }
198
199 if (interval_ms) {
200 *interval_ms = 0;
201 }
202
203 CRM_CHECK(key && *key, return FALSE);
204
205 underbar1 = strchr(key, '_');
206 if (!underbar1) {
207 return FALSE;
208 }
209
210 underbar2 = strchr(underbar1+1, '_');
211 if (!underbar2) {
212 return FALSE;
213 }
214
215 underbar3 = strchr(underbar2+1, '_');
216
217 if (!underbar3) {
218 return try_fast_match(key, underbar1, underbar2,
219 rsc_id, op_type, interval_ms);
220 } else if (try_migrate_notify_match(key, rsc_id, op_type, interval_ms)) {
221 return TRUE;
222 } else {
223 return try_basic_match(key, rsc_id, op_type, interval_ms);
224 }
225 }
226
227 char *
228 pcmk__notify_key(const char *rsc_id, const char *notify_type,
229 const char *op_type)
230 {
231 CRM_CHECK(rsc_id != NULL, return NULL);
232 CRM_CHECK(op_type != NULL, return NULL);
233 CRM_CHECK(notify_type != NULL, return NULL);
234 return crm_strdup_printf("%s_%s_notify_%s_0",
235 rsc_id, notify_type, op_type);
236 }
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253 gboolean
254 decode_transition_magic(const char *magic, char **uuid, int *transition_id, int *action_id,
255 int *op_status, int *op_rc, int *target_rc)
256 {
257 int res = 0;
258 char *key = NULL;
259 gboolean result = TRUE;
260 int local_op_status = -1;
261 int local_op_rc = -1;
262
263 CRM_CHECK(magic != NULL, return FALSE);
264
265 #ifdef SSCANF_HAS_M
266 res = sscanf(magic, "%d:%d;%ms", &local_op_status, &local_op_rc, &key);
267 #else
268 key = calloc(1, strlen(magic) - 3);
269 CRM_ASSERT(key);
270 res = sscanf(magic, "%d:%d;%s", &local_op_status, &local_op_rc, key);
271 #endif
272 if (res == EOF) {
273 crm_err("Could not decode transition information '%s': %s",
274 magic, pcmk_strerror(errno));
275 result = FALSE;
276 } else if (res < 3) {
277 crm_warn("Transition information '%s' incomplete (%d of 3 expected items)",
278 magic, res);
279 result = FALSE;
280 } else {
281 if (op_status) {
282 *op_status = local_op_status;
283 }
284 if (op_rc) {
285 *op_rc = local_op_rc;
286 }
287 result = decode_transition_key(key, uuid, transition_id, action_id,
288 target_rc);
289 }
290 free(key);
291 return result;
292 }
293
294 char *
295 pcmk__transition_key(int transition_id, int action_id, int target_rc,
296 const char *node)
297 {
298 CRM_CHECK(node != NULL, return NULL);
299 return crm_strdup_printf("%d:%d:%d:%-*s",
300 action_id, transition_id, target_rc, 36, node);
301 }
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316 gboolean
317 decode_transition_key(const char *key, char **uuid, int *transition_id, int *action_id,
318 int *target_rc)
319 {
320 int local_transition_id = -1;
321 int local_action_id = -1;
322 int local_target_rc = -1;
323 char local_uuid[37] = { '\0' };
324
325
326 if (uuid) {
327 *uuid = NULL;
328 }
329 if (transition_id) {
330 *transition_id = -1;
331 }
332 if (action_id) {
333 *action_id = -1;
334 }
335 if (target_rc) {
336 *target_rc = -1;
337 }
338
339 CRM_CHECK(key != NULL, return FALSE);
340 if (sscanf(key, "%d:%d:%d:%36s", &local_action_id, &local_transition_id,
341 &local_target_rc, local_uuid) != 4) {
342 crm_err("Invalid transition key '%s'", key);
343 return FALSE;
344 }
345 if (strlen(local_uuid) != 36) {
346 crm_warn("Invalid UUID '%s' in transition key '%s'", local_uuid, key);
347 }
348 if (uuid) {
349 *uuid = strdup(local_uuid);
350 CRM_ASSERT(*uuid);
351 }
352 if (transition_id) {
353 *transition_id = local_transition_id;
354 }
355 if (action_id) {
356 *action_id = local_action_id;
357 }
358 if (target_rc) {
359 *target_rc = local_target_rc;
360 }
361 return TRUE;
362 }
363
364
365
366
367
368
369
370 void
371 pcmk__filter_op_for_digest(xmlNode *param_set)
372 {
373 char *key = NULL;
374 char *timeout = NULL;
375 guint interval_ms = 0;
376
377 const char *attr_filter[] = {
378 XML_ATTR_ID,
379 XML_ATTR_CRM_VERSION,
380 XML_LRM_ATTR_OP_DIGEST,
381 XML_LRM_ATTR_TARGET,
382 XML_LRM_ATTR_TARGET_UUID,
383 "pcmk_external_ip"
384 };
385
386 const int meta_len = strlen(CRM_META);
387
388 if (param_set == NULL) {
389 return;
390 }
391
392
393 for (int lpc = 0; lpc < DIMOF(attr_filter); lpc++) {
394 xml_remove_prop(param_set, attr_filter[lpc]);
395 }
396
397 key = crm_meta_name(XML_LRM_ATTR_INTERVAL_MS);
398 if (crm_element_value_ms(param_set, key, &interval_ms) != pcmk_ok) {
399 interval_ms = 0;
400 }
401 free(key);
402
403 key = crm_meta_name(XML_ATTR_TIMEOUT);
404 timeout = crm_element_value_copy(param_set, key);
405
406
407 for (xmlAttrPtr xIter = param_set->properties; xIter != NULL; ) {
408 const char *prop_name = (const char *) (xIter->name);
409
410 xIter = xIter->next;
411
412
413 if (strncasecmp(prop_name, CRM_META, meta_len) == 0) {
414 xml_remove_prop(param_set, prop_name);
415 }
416 }
417
418 if ((interval_ms != 0) && (timeout != NULL)) {
419
420 crm_xml_add(param_set, key, timeout);
421 }
422
423 free(timeout);
424 free(key);
425 }
426
427 int
428 rsc_op_expected_rc(lrmd_event_data_t * op)
429 {
430 int rc = 0;
431
432 if (op && op->user_data) {
433 decode_transition_key(op->user_data, NULL, NULL, NULL, &rc);
434 }
435 return rc;
436 }
437
438 gboolean
439 did_rsc_op_fail(lrmd_event_data_t * op, int target_rc)
440 {
441 switch (op->op_status) {
442 case PCMK_LRM_OP_CANCELLED:
443 case PCMK_LRM_OP_PENDING:
444 return FALSE;
445
446 case PCMK_LRM_OP_NOTSUPPORTED:
447 case PCMK_LRM_OP_TIMEOUT:
448 case PCMK_LRM_OP_ERROR:
449 case PCMK_LRM_OP_NOT_CONNECTED:
450 case PCMK_LRM_OP_INVALID:
451 return TRUE;
452
453 default:
454 if (target_rc != op->rc) {
455 return TRUE;
456 }
457 }
458
459 return FALSE;
460 }
461
462
463
464
465
466
467
468
469
470
471
472
473 xmlNode *
474 crm_create_op_xml(xmlNode *parent, const char *prefix, const char *task,
475 const char *interval_spec, const char *timeout)
476 {
477 xmlNode *xml_op;
478
479 CRM_CHECK(prefix && task && interval_spec, return NULL);
480
481 xml_op = create_xml_node(parent, XML_ATTR_OP);
482 crm_xml_set_id(xml_op, "%s-%s-%s", prefix, task, interval_spec);
483 crm_xml_add(xml_op, XML_LRM_ATTR_INTERVAL, interval_spec);
484 crm_xml_add(xml_op, "name", task);
485 if (timeout) {
486 crm_xml_add(xml_op, XML_ATTR_TIMEOUT, timeout);
487 }
488 return xml_op;
489 }
490
491
492
493
494
495
496
497
498
499
500 bool
501 crm_op_needs_metadata(const char *rsc_class, const char *op)
502 {
503
504
505
506
507
508 CRM_CHECK((rsc_class != NULL) || (op != NULL), return false);
509
510 if ((rsc_class != NULL)
511 && !pcmk_is_set(pcmk_get_ra_caps(rsc_class), pcmk_ra_cap_params)) {
512
513 return false;
514 }
515 if (op == NULL) {
516 return true;
517 }
518
519
520 return pcmk__str_any_of(op, CRMD_ACTION_START, CRMD_ACTION_STATUS,
521 CRMD_ACTION_PROMOTE, CRMD_ACTION_DEMOTE,
522 CRMD_ACTION_RELOAD, CRMD_ACTION_MIGRATE,
523 CRMD_ACTION_MIGRATED, CRMD_ACTION_NOTIFY, NULL);
524 }