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, pcmk_resource_t *rsc,
100 const pcmk_node_t *node, GHashTable *params,
101 const char *task, guint *interval_ms,
102 const xmlNode *xml_op, const char *op_version,
103 GHashTable *overrides, pcmk_scheduler_t *scheduler)
104 {
105 xmlNode *action_config = 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, scheduler, data->params_all,
113 XML_RSC_ATTR_REMOTE_RA_ADDR);
114
115 if (overrides != NULL) {
116
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 g_hash_table_foreach(overrides, hash2field, data->params_all);
131 }
132
133
134 g_hash_table_foreach(params, hash2field, data->params_all);
135
136
137 action_config = pcmk__find_action_config(rsc, task, *interval_ms, true);
138
139
140
141
142
143
144
145
146
147
148
149 params = pcmk__unpack_action_rsc_params(action_config, node->details->attrs,
150 scheduler);
151 if ((*interval_ms == 0) && (g_hash_table_size(params) > 0)) {
152 data->rc = pcmk__digest_restart;
153 }
154 g_hash_table_foreach(params, hash2field, data->params_all);
155 g_hash_table_destroy(params);
156
157
158 params = pcmk__unpack_action_meta(rsc, node, task, *interval_ms,
159 action_config);
160 g_hash_table_foreach(params, hash2metafield, data->params_all);
161 g_hash_table_destroy(params);
162
163 pcmk__filter_op_for_digest(data->params_all);
164
165 data->digest_all_calc = calculate_operation_digest(data->params_all,
166 op_version);
167 }
168
169
170 static bool
171 is_fence_param(xmlAttrPtr attr, void *user_data)
172 {
173 return pcmk_stonith_param((const char *) attr->name);
174 }
175
176
177
178
179
180
181
182
183
184
185
186
187 static void
188 calculate_secure_digest(op_digest_cache_t *data, const pcmk_resource_t *rsc,
189 GHashTable *params, const xmlNode *xml_op,
190 const char *op_version, GHashTable *overrides)
191 {
192 const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
193 const char *secure_list = NULL;
194 bool old_version = (compare_version(op_version, "3.16.0") < 0);
195
196 if (xml_op == NULL) {
197 secure_list = " passwd password user ";
198 } else {
199 secure_list = crm_element_value(xml_op, XML_LRM_ATTR_OP_SECURE);
200 }
201
202 if (old_version) {
203 data->params_secure = create_xml_node(NULL, XML_TAG_PARAMS);
204 if (overrides != NULL) {
205 g_hash_table_foreach(overrides, hash2field, data->params_secure);
206 }
207
208 g_hash_table_foreach(params, hash2field, data->params_secure);
209
210 } else {
211
212 data->params_secure = copy_xml(data->params_all);
213 }
214
215 if (secure_list != NULL) {
216 pcmk__xe_remove_matching_attrs(data->params_secure, attr_in_string,
217 (void *) secure_list);
218 }
219 if (old_version
220 && pcmk_is_set(pcmk_get_ra_caps(class),
221 pcmk_ra_cap_fence_params)) {
222
223
224
225
226
227 pcmk__xe_remove_matching_attrs(data->params_secure, is_fence_param,
228 NULL);
229 }
230 pcmk__filter_op_for_digest(data->params_secure);
231
232
233
234
235
236
237
238 if (old_version) {
239 xml_remove_prop(data->params_secure, CRM_META "_" XML_ATTR_TIMEOUT);
240 }
241
242 data->digest_secure_calc = calculate_operation_digest(data->params_secure,
243 op_version);
244 }
245
246
247
248
249
250
251
252
253
254
255
256
257 static void
258 calculate_restart_digest(op_digest_cache_t *data, const xmlNode *xml_op,
259 const char *op_version)
260 {
261 const char *value = NULL;
262
263
264 if (xml_op == NULL) {
265 return;
266 }
267
268
269 if (crm_element_value(xml_op, XML_LRM_ATTR_RESTART_DIGEST) == NULL) {
270 return;
271 }
272
273
274 data->params_restart = copy_xml(data->params_all);
275
276
277 value = crm_element_value(xml_op, XML_LRM_ATTR_OP_RESTART);
278 if (value != NULL) {
279 pcmk__xe_remove_matching_attrs(data->params_restart, attr_not_in_string,
280 (void *) value);
281 }
282
283 value = crm_element_value(xml_op, XML_ATTR_CRM_VERSION);
284 data->digest_restart_calc = calculate_operation_digest(data->params_restart,
285 value);
286 }
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305 op_digest_cache_t *
306 pe__calculate_digests(pcmk_resource_t *rsc, const char *task,
307 guint *interval_ms, const pcmk_node_t *node,
308 const xmlNode *xml_op, GHashTable *overrides,
309 bool calc_secure, pcmk_scheduler_t *scheduler)
310 {
311 op_digest_cache_t *data = calloc(1, sizeof(op_digest_cache_t));
312 const char *op_version = NULL;
313 GHashTable *params = NULL;
314
315 if (data == NULL) {
316 return NULL;
317 }
318
319 data->rc = pcmk__digest_match;
320
321 if (xml_op != NULL) {
322 op_version = crm_element_value(xml_op, XML_ATTR_CRM_VERSION);
323 }
324
325 if (op_version == NULL && scheduler != NULL && scheduler->input != NULL) {
326 op_version = crm_element_value(scheduler->input, XML_ATTR_CRM_VERSION);
327 }
328
329 if (op_version == NULL) {
330 op_version = CRM_FEATURE_SET;
331 }
332
333 params = pe_rsc_params(rsc, node, scheduler);
334 calculate_main_digest(data, rsc, node, params, task, interval_ms, xml_op,
335 op_version, overrides, scheduler);
336 if (calc_secure) {
337 calculate_secure_digest(data, rsc, params, xml_op, op_version,
338 overrides);
339 }
340 calculate_restart_digest(data, xml_op, op_version);
341 return data;
342 }
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358 static op_digest_cache_t *
359 rsc_action_digest(pcmk_resource_t *rsc, const char *task, guint interval_ms,
360 pcmk_node_t *node, const xmlNode *xml_op,
361 bool calc_secure, pcmk_scheduler_t *scheduler)
362 {
363 op_digest_cache_t *data = NULL;
364 char *key = pcmk__op_key(rsc->id, task, interval_ms);
365
366 data = g_hash_table_lookup(node->details->digest_cache, key);
367 if (data == NULL) {
368 data = pe__calculate_digests(rsc, task, &interval_ms, node, xml_op,
369 NULL, calc_secure, scheduler);
370 CRM_ASSERT(data != NULL);
371 g_hash_table_insert(node->details->digest_cache, strdup(key), data);
372 }
373 free(key);
374 return data;
375 }
376
377
378
379
380
381
382
383
384
385
386
387
388 op_digest_cache_t *
389 rsc_action_digest_cmp(pcmk_resource_t *rsc, const xmlNode *xml_op,
390 pcmk_node_t *node, pcmk_scheduler_t *scheduler)
391 {
392 op_digest_cache_t *data = NULL;
393 guint interval_ms = 0;
394
395 const char *op_version;
396 const char *task = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
397 const char *digest_all;
398 const char *digest_restart;
399
400 CRM_ASSERT(node != NULL);
401
402 op_version = crm_element_value(xml_op, XML_ATTR_CRM_VERSION);
403 digest_all = crm_element_value(xml_op, XML_LRM_ATTR_OP_DIGEST);
404 digest_restart = crm_element_value(xml_op, XML_LRM_ATTR_RESTART_DIGEST);
405
406 crm_element_value_ms(xml_op, XML_LRM_ATTR_INTERVAL_MS, &interval_ms);
407 data = rsc_action_digest(rsc, task, interval_ms, node, xml_op,
408 pcmk_is_set(scheduler->flags,
409 pcmk_sched_sanitized),
410 scheduler);
411
412 if (digest_restart && data->digest_restart_calc && strcmp(data->digest_restart_calc, digest_restart) != 0) {
413 pe_rsc_info(rsc, "Parameters to %ums-interval %s action for %s on %s "
414 "changed: hash was %s vs. now %s (restart:%s) %s",
415 interval_ms, task, rsc->id, pe__node_name(node),
416 pcmk__s(digest_restart, "missing"),
417 data->digest_restart_calc,
418 op_version,
419 crm_element_value(xml_op, XML_ATTR_TRANSITION_MAGIC));
420 data->rc = pcmk__digest_restart;
421
422 } else if (digest_all == NULL) {
423
424 data->rc = pcmk__digest_unknown;
425
426 } else if (strcmp(digest_all, data->digest_all_calc) != 0) {
427
428
429
430
431
432
433
434
435
436 if ((interval_ms == 0) && (data->rc == pcmk__digest_restart)) {
437 pe_rsc_info(rsc, "Parameters containing extra ones to %ums-interval"
438 " %s action for %s on %s "
439 "changed: hash was %s vs. now %s (restart:%s) %s",
440 interval_ms, task, rsc->id, pe__node_name(node),
441 pcmk__s(digest_all, "missing"), data->digest_all_calc,
442 op_version,
443 crm_element_value(xml_op, XML_ATTR_TRANSITION_MAGIC));
444
445 } else {
446 pe_rsc_info(rsc, "Parameters to %ums-interval %s action for %s on %s "
447 "changed: hash was %s vs. now %s (%s:%s) %s",
448 interval_ms, task, rsc->id, pe__node_name(node),
449 pcmk__s(digest_all, "missing"), data->digest_all_calc,
450 (interval_ms > 0)? "reschedule" : "reload",
451 op_version,
452 crm_element_value(xml_op, XML_ATTR_TRANSITION_MAGIC));
453 data->rc = pcmk__digest_mismatch;
454 }
455
456 } else {
457 data->rc = pcmk__digest_match;
458 }
459 return data;
460 }
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479 static inline char *
480 create_unfencing_summary(const char *rsc_id, const char *agent_type,
481 const char *param_digest)
482 {
483 return crm_strdup_printf("%s:%s:%s", rsc_id, agent_type, param_digest);
484 }
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502 static bool
503 unfencing_digest_matches(const char *rsc_id, const char *agent,
504 const char *digest_calc, const char *node_summary)
505 {
506 bool matches = FALSE;
507
508 if (rsc_id && agent && digest_calc && node_summary) {
509 char *search_secure = create_unfencing_summary(rsc_id, agent,
510 digest_calc);
511
512
513
514
515 matches = (strstr(node_summary, search_secure) != NULL);
516 crm_trace("Calculated unfencing digest '%s' %sfound in '%s'",
517 search_secure, matches? "" : "not ", node_summary);
518 free(search_secure);
519 }
520 return matches;
521 }
522
523
524
525
526
527 #define STONITH_DIGEST_TASK "stonith-on"
528
529
530
531
532
533
534
535
536
537
538
539
540 op_digest_cache_t *
541 pe__compare_fencing_digest(pcmk_resource_t *rsc, const char *agent,
542 pcmk_node_t *node, pcmk_scheduler_t *scheduler)
543 {
544 const char *node_summary = NULL;
545
546
547 op_digest_cache_t *data = rsc_action_digest(rsc, STONITH_DIGEST_TASK, 0U,
548 node, NULL, TRUE, scheduler);
549
550
551 node_summary = pe_node_attribute_raw(node, CRM_ATTR_DIGESTS_ALL);
552 if (node_summary == NULL) {
553 data->rc = pcmk__digest_unknown;
554 return data;
555 }
556
557
558 if (unfencing_digest_matches(rsc->id, agent, data->digest_all_calc,
559 node_summary)) {
560 data->rc = pcmk__digest_match;
561 return data;
562 }
563
564
565 node_summary = pe_node_attribute_raw(node, CRM_ATTR_DIGESTS_SECURE);
566 if (unfencing_digest_matches(rsc->id, agent, data->digest_secure_calc,
567 node_summary)) {
568 data->rc = pcmk__digest_match;
569 if (!pcmk__is_daemon && scheduler->priv != NULL) {
570 pcmk__output_t *out = scheduler->priv;
571 out->info(out, "Only 'private' parameters to %s "
572 "for unfencing %s changed", rsc->id,
573 pe__node_name(node));
574 }
575 return data;
576 }
577
578
579 data->rc = pcmk__digest_mismatch;
580 if (pcmk_is_set(scheduler->flags, pcmk_sched_sanitized)
581 && (data->digest_secure_calc != NULL)) {
582
583 if (scheduler->priv != NULL) {
584 pcmk__output_t *out = scheduler->priv;
585 char *digest = create_unfencing_summary(rsc->id, agent,
586 data->digest_secure_calc);
587
588 out->info(out, "Parameters to %s for unfencing "
589 "%s changed, try '%s'", rsc->id,
590 pe__node_name(node), digest);
591 free(digest);
592 } else if (!pcmk__is_daemon) {
593 char *digest = create_unfencing_summary(rsc->id, agent,
594 data->digest_secure_calc);
595
596 printf("Parameters to %s for unfencing %s changed, try '%s'\n",
597 rsc->id, pe__node_name(node), digest);
598 free(digest);
599 }
600 }
601 return data;
602 }