This source file includes following definitions.
- pe__free_digests
- attr_not_in_string
- attr_in_string
- calculate_main_digest
- is_fence_param
- calculate_secure_digest
- calculate_restart_digest
- pe__calculate_digests
- rsc_action_digest
- rsc_action_digest_cmp
- create_unfencing_summary
- unfencing_digest_matches
- pe__compare_fencing_digest
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <glib.h>
13 #include <stdbool.h>
14
15 #include <crm/crm.h>
16 #include <crm/common/xml.h>
17 #include <crm/common/xml_internal.h>
18 #include <crm/pengine/internal.h>
19 #include "pe_status_private.h"
20
21 extern bool pcmk__is_daemon;
22
23
24
25
26
27
28
29
30
31
32 void
33 pe__free_digests(gpointer ptr)
34 {
35 pcmk__op_digest_t *data = ptr;
36
37 if (data != NULL) {
38 pcmk__xml_free(data->params_all);
39 pcmk__xml_free(data->params_secure);
40 pcmk__xml_free(data->params_restart);
41
42 free(data->digest_all_calc);
43 free(data->digest_restart_calc);
44 free(data->digest_secure_calc);
45
46 free(data);
47 }
48 }
49
50
51 static bool
52 attr_not_in_string(xmlAttrPtr a, void *user_data)
53 {
54 bool filter = false;
55 char *name = crm_strdup_printf(" %s ", (const char *) a->name);
56
57 if (strstr((const char *) user_data, name) == NULL) {
58 crm_trace("Filtering %s (not found in '%s')",
59 (const char *) a->name, (const char *) user_data);
60 filter = true;
61 }
62 free(name);
63 return filter;
64 }
65
66
67 static bool
68 attr_in_string(xmlAttrPtr a, void *user_data)
69 {
70 bool filter = false;
71 char *name = crm_strdup_printf(" %s ", (const char *) a->name);
72
73 if (strstr((const char *) user_data, name) != NULL) {
74 crm_trace("Filtering %s (found in '%s')",
75 (const char *) a->name, (const char *) user_data);
76 filter = true;
77 }
78 free(name);
79 return filter;
80 }
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97 static void
98 calculate_main_digest(pcmk__op_digest_t *data, pcmk_resource_t *rsc,
99 const pcmk_node_t *node, GHashTable *params,
100 const char *task, guint *interval_ms,
101 const xmlNode *xml_op, const char *op_version,
102 GHashTable *overrides, pcmk_scheduler_t *scheduler)
103 {
104 xmlNode *action_config = NULL;
105
106 data->params_all = pcmk__xe_create(NULL, PCMK_XE_PARAMETERS);
107
108
109
110
111 (void) pe__add_bundle_remote_name(rsc, data->params_all,
112 PCMK_REMOTE_RA_ADDR);
113
114 if (overrides != NULL) {
115
116 const char *meta_name = CRM_META "_" PCMK_META_INTERVAL;
117 const char *interval_s = g_hash_table_lookup(overrides, meta_name);
118
119 if (interval_s != NULL) {
120 long long value_ll;
121
122 if ((pcmk__scan_ll(interval_s, &value_ll, 0LL) == pcmk_rc_ok)
123 && (value_ll >= 0) && (value_ll <= G_MAXUINT)) {
124 *interval_ms = (guint) value_ll;
125 }
126 }
127
128
129 g_hash_table_foreach(overrides, hash2field, data->params_all);
130 }
131
132
133 g_hash_table_foreach(params, hash2field, data->params_all);
134
135
136 action_config = pcmk__find_action_config(rsc, task, *interval_ms, true);
137
138
139
140
141
142
143
144
145
146
147
148 params = pcmk__unpack_action_rsc_params(action_config, node->priv->attrs,
149 scheduler);
150 if ((*interval_ms == 0) && (g_hash_table_size(params) > 0)) {
151 data->rc = pcmk__digest_restart;
152 }
153 g_hash_table_foreach(params, hash2field, data->params_all);
154 g_hash_table_destroy(params);
155
156
157 params = pcmk__unpack_action_meta(rsc, node, task, *interval_ms,
158 action_config);
159 g_hash_table_foreach(params, hash2metafield, data->params_all);
160 g_hash_table_destroy(params);
161
162 pcmk__filter_op_for_digest(data->params_all);
163
164 data->digest_all_calc = pcmk__digest_operation(data->params_all);
165 }
166
167
168 static bool
169 is_fence_param(xmlAttrPtr attr, void *user_data)
170 {
171 return pcmk_stonith_param((const char *) attr->name);
172 }
173
174
175
176
177
178
179
180
181
182
183
184
185 static void
186 calculate_secure_digest(pcmk__op_digest_t *data, const pcmk_resource_t *rsc,
187 GHashTable *params, const xmlNode *xml_op,
188 const char *op_version, GHashTable *overrides)
189 {
190 const char *class = crm_element_value(rsc->priv->xml, PCMK_XA_CLASS);
191 const char *secure_list = NULL;
192 bool old_version = (compare_version(op_version, "3.16.0") < 0);
193
194 if (xml_op == NULL) {
195 secure_list = " passwd password user ";
196 } else {
197 secure_list = crm_element_value(xml_op, PCMK__XA_OP_SECURE_PARAMS);
198 }
199
200 if (old_version) {
201 data->params_secure = pcmk__xe_create(NULL, PCMK_XE_PARAMETERS);
202 if (overrides != NULL) {
203 g_hash_table_foreach(overrides, hash2field, data->params_secure);
204 }
205
206 g_hash_table_foreach(params, hash2field, data->params_secure);
207
208 } else {
209
210 data->params_secure = pcmk__xml_copy(NULL, data->params_all);
211 }
212
213 if (secure_list != NULL) {
214 pcmk__xe_remove_matching_attrs(data->params_secure, attr_in_string,
215 (void *) secure_list);
216 }
217 if (old_version
218 && pcmk_is_set(pcmk_get_ra_caps(class),
219 pcmk_ra_cap_fence_params)) {
220
221
222
223
224
225 pcmk__xe_remove_matching_attrs(data->params_secure, is_fence_param,
226 NULL);
227 }
228 pcmk__filter_op_for_digest(data->params_secure);
229
230
231
232
233
234
235
236 if (old_version) {
237 pcmk__xe_remove_attr(data->params_secure,
238 CRM_META "_" PCMK_META_TIMEOUT);
239 }
240
241 data->digest_secure_calc = pcmk__digest_operation(data->params_secure);
242 }
243
244
245
246
247
248
249
250
251
252
253
254
255 static void
256 calculate_restart_digest(pcmk__op_digest_t *data, const xmlNode *xml_op,
257 const char *op_version)
258 {
259 const char *value = NULL;
260
261
262 if (xml_op == NULL) {
263 return;
264 }
265
266
267 if (crm_element_value(xml_op, PCMK__XA_OP_RESTART_DIGEST) == NULL) {
268 return;
269 }
270
271
272 data->params_restart = pcmk__xml_copy(NULL, data->params_all);
273
274
275 value = crm_element_value(xml_op, PCMK__XA_OP_FORCE_RESTART);
276 if (value != NULL) {
277 pcmk__xe_remove_matching_attrs(data->params_restart, attr_not_in_string,
278 (void *) value);
279 }
280
281 value = crm_element_value(xml_op, PCMK_XA_CRM_FEATURE_SET);
282 data->digest_restart_calc = pcmk__digest_operation(data->params_restart);
283 }
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302 pcmk__op_digest_t *
303 pe__calculate_digests(pcmk_resource_t *rsc, const char *task,
304 guint *interval_ms, const pcmk_node_t *node,
305 const xmlNode *xml_op, GHashTable *overrides,
306 bool calc_secure, pcmk_scheduler_t *scheduler)
307 {
308 pcmk__op_digest_t *data = NULL;
309 const char *op_version = NULL;
310 GHashTable *params = NULL;
311
312 CRM_CHECK(scheduler != NULL, return NULL);
313
314 data = calloc(1, sizeof(pcmk__op_digest_t));
315 if (data == NULL) {
316 pcmk__sched_err(scheduler,
317 "Could not allocate memory for operation digest");
318 return NULL;
319 }
320
321 data->rc = pcmk__digest_match;
322
323 if (xml_op != NULL) {
324 op_version = crm_element_value(xml_op, PCMK_XA_CRM_FEATURE_SET);
325 }
326
327 if ((op_version == NULL) && (scheduler->input != NULL)) {
328 op_version = crm_element_value(scheduler->input,
329 PCMK_XA_CRM_FEATURE_SET);
330 }
331
332 if (op_version == NULL) {
333 op_version = CRM_FEATURE_SET;
334 }
335
336 params = pe_rsc_params(rsc, node, scheduler);
337 calculate_main_digest(data, rsc, node, params, task, interval_ms, xml_op,
338 op_version, overrides, scheduler);
339 if (calc_secure) {
340 calculate_secure_digest(data, rsc, params, xml_op, op_version,
341 overrides);
342 }
343 calculate_restart_digest(data, xml_op, op_version);
344 return data;
345 }
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361 static pcmk__op_digest_t *
362 rsc_action_digest(pcmk_resource_t *rsc, const char *task, guint interval_ms,
363 pcmk_node_t *node, const xmlNode *xml_op,
364 bool calc_secure, pcmk_scheduler_t *scheduler)
365 {
366 pcmk__op_digest_t *data = NULL;
367 char *key = pcmk__op_key(rsc->id, task, interval_ms);
368
369 data = g_hash_table_lookup(node->priv->digest_cache, key);
370 if (data == NULL) {
371 data = pe__calculate_digests(rsc, task, &interval_ms, node, xml_op,
372 NULL, calc_secure, scheduler);
373 pcmk__assert(data != NULL);
374 g_hash_table_insert(node->priv->digest_cache, strdup(key), data);
375 }
376 free(key);
377 return data;
378 }
379
380
381
382
383
384
385
386
387
388
389
390
391 pcmk__op_digest_t *
392 rsc_action_digest_cmp(pcmk_resource_t *rsc, const xmlNode *xml_op,
393 pcmk_node_t *node, pcmk_scheduler_t *scheduler)
394 {
395 pcmk__op_digest_t *data = NULL;
396 guint interval_ms = 0;
397
398 const char *op_version;
399 const char *task = crm_element_value(xml_op, PCMK_XA_OPERATION);
400 const char *digest_all;
401 const char *digest_restart;
402
403 pcmk__assert(node != NULL);
404
405 op_version = crm_element_value(xml_op, PCMK_XA_CRM_FEATURE_SET);
406 digest_all = crm_element_value(xml_op, PCMK__XA_OP_DIGEST);
407 digest_restart = crm_element_value(xml_op, PCMK__XA_OP_RESTART_DIGEST);
408
409 crm_element_value_ms(xml_op, PCMK_META_INTERVAL, &interval_ms);
410 data = rsc_action_digest(rsc, task, interval_ms, node, xml_op,
411 pcmk_is_set(scheduler->flags,
412 pcmk__sched_sanitized),
413 scheduler);
414
415 if (digest_restart && data->digest_restart_calc && strcmp(data->digest_restart_calc, digest_restart) != 0) {
416 pcmk__rsc_info(rsc,
417 "Parameters to %ums-interval %s action for %s on %s "
418 "changed: hash was %s vs. now %s (restart:%s) %s",
419 interval_ms, task, rsc->id, pcmk__node_name(node),
420 pcmk__s(digest_restart, "missing"),
421 data->digest_restart_calc, op_version,
422 crm_element_value(xml_op, PCMK__XA_TRANSITION_MAGIC));
423 data->rc = pcmk__digest_restart;
424
425 } else if (digest_all == NULL) {
426
427 data->rc = pcmk__digest_unknown;
428
429 } else if (strcmp(digest_all, data->digest_all_calc) != 0) {
430
431
432
433
434
435
436
437
438
439 if ((interval_ms == 0) && (data->rc == pcmk__digest_restart)) {
440 pcmk__rsc_info(rsc,
441 "Parameters containing extra ones to %ums-interval"
442 " %s action for %s on %s "
443 "changed: hash was %s vs. now %s (restart:%s) %s",
444 interval_ms, task, rsc->id, pcmk__node_name(node),
445 pcmk__s(digest_all, "missing"),
446 data->digest_all_calc, op_version,
447 crm_element_value(xml_op,
448 PCMK__XA_TRANSITION_MAGIC));
449
450 } else {
451 pcmk__rsc_info(rsc,
452 "Parameters to %ums-interval %s action for %s on %s "
453 "changed: hash was %s vs. now %s (%s:%s) %s",
454 interval_ms, task, rsc->id, pcmk__node_name(node),
455 pcmk__s(digest_all, "missing"),
456 data->digest_all_calc,
457 (interval_ms > 0)? "reschedule" : "reload",
458 op_version,
459 crm_element_value(xml_op,
460 PCMK__XA_TRANSITION_MAGIC));
461 data->rc = pcmk__digest_mismatch;
462 }
463
464 } else {
465 data->rc = pcmk__digest_match;
466 }
467 return data;
468 }
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487 static inline char *
488 create_unfencing_summary(const char *rsc_id, const char *agent_type,
489 const char *param_digest)
490 {
491 return crm_strdup_printf("%s:%s:%s", rsc_id, agent_type, param_digest);
492 }
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510 static bool
511 unfencing_digest_matches(const char *rsc_id, const char *agent,
512 const char *digest_calc, const char *node_summary)
513 {
514 bool matches = FALSE;
515
516 if (rsc_id && agent && digest_calc && node_summary) {
517 char *search_secure = create_unfencing_summary(rsc_id, agent,
518 digest_calc);
519
520
521
522
523 matches = (strstr(node_summary, search_secure) != NULL);
524 crm_trace("Calculated unfencing digest '%s' %sfound in '%s'",
525 search_secure, matches? "" : "not ", node_summary);
526 free(search_secure);
527 }
528 return matches;
529 }
530
531
532
533
534
535 #define STONITH_DIGEST_TASK "stonith-on"
536
537
538
539
540
541
542
543
544
545
546
547
548 pcmk__op_digest_t *
549 pe__compare_fencing_digest(pcmk_resource_t *rsc, const char *agent,
550 pcmk_node_t *node, pcmk_scheduler_t *scheduler)
551 {
552 const char *node_summary = NULL;
553
554
555 pcmk__op_digest_t *data = rsc_action_digest(rsc, STONITH_DIGEST_TASK, 0U,
556 node, NULL, TRUE, scheduler);
557
558
559 node_summary = pcmk__node_attr(node, CRM_ATTR_DIGESTS_ALL, NULL,
560 pcmk__rsc_node_current);
561 if (node_summary == NULL) {
562 data->rc = pcmk__digest_unknown;
563 return data;
564 }
565
566
567 if (unfencing_digest_matches(rsc->id, agent, data->digest_all_calc,
568 node_summary)) {
569 data->rc = pcmk__digest_match;
570 return data;
571 }
572
573
574 node_summary = pcmk__node_attr(node, CRM_ATTR_DIGESTS_SECURE, NULL,
575 pcmk__rsc_node_current);
576 if (unfencing_digest_matches(rsc->id, agent, data->digest_secure_calc,
577 node_summary)) {
578 data->rc = pcmk__digest_match;
579 if (!pcmk__is_daemon && (scheduler->priv->out != NULL)) {
580 pcmk__output_t *out = scheduler->priv->out;
581
582 out->info(out, "Only 'private' parameters to %s "
583 "for unfencing %s changed", rsc->id,
584 pcmk__node_name(node));
585 }
586 return data;
587 }
588
589
590 data->rc = pcmk__digest_mismatch;
591 if (pcmk_is_set(scheduler->flags, pcmk__sched_sanitized)
592 && (data->digest_secure_calc != NULL)) {
593
594 if (scheduler->priv->out != NULL) {
595 pcmk__output_t *out = scheduler->priv->out;
596 char *digest = create_unfencing_summary(rsc->id, agent,
597 data->digest_secure_calc);
598
599 out->info(out, "Parameters to %s for unfencing "
600 "%s changed, try '%s'", rsc->id,
601 pcmk__node_name(node), digest);
602 free(digest);
603 } else if (!pcmk__is_daemon) {
604 char *digest = create_unfencing_summary(rsc->id, agent,
605 data->digest_secure_calc);
606
607 printf("Parameters to %s for unfencing %s changed, try '%s'\n",
608 rsc->id, pcmk__node_name(node), digest);
609 free(digest);
610 }
611 }
612 return data;
613 }