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