1    	/*
2    	 * Copyright 2006-2026 the Pacemaker project contributors
3    	 *
4    	 * The version control history for this file may have further details.
5    	 *
6    	 * This source code is licensed under the GNU General Public License version 2
7    	 * or later (GPLv2+) WITHOUT ANY WARRANTY.
8    	 */
9    	
10   	#include <crm_internal.h>
11   	
12   	#include <stdbool.h>
13   	
14   	#include <crm/crm.h>
15   	#include <crm/common/ipc.h>
16   	#include <crm/common/xml.h>
17   	
18   	#include <pacemaker-controld.h>
19   	
20   	static pcmk_ipc_api_t *attrd_api = NULL;
21   	
22   	void
23   	controld_close_attrd_ipc(void)
24   	{
(1) Event path: Condition "attrd_api == NULL", taking false branch.
25   	    if (attrd_api == NULL) {
26   	        return;
27   	    }
28   	
(2) Event path: Switch case default.
(3) Event path: Condition "trace_cs == NULL", taking true branch.
(4) Event path: Condition "crm_is_callsite_active(trace_cs, _level, 0)", taking false branch.
(5) Event path: Breaking from switch.
29   	    pcmk__trace("Closing connection to " PCMK__SERVER_ATTRD);
30   	    pcmk_disconnect_ipc(attrd_api);
CID (unavailable; MK=365118909805af1f9bc248c73473cee4) (#1 of 1): Inconsistent C union access (INCONSISTENT_UNION_ACCESS):
(6) Event assign_union_field: The union field "in" of "_pp" is written.
(7) Event inconsistent_union_field_access: In "_pp.out", the union field used: "out" is inconsistent with the field most recently stored: "in".
31   	    g_clear_pointer(&attrd_api, pcmk_free_ipc_api);
32   	}
33   	
34   	static inline const char *
35   	node_type(bool is_remote)
36   	{
37   	    return is_remote? "Pacemaker Remote" : "cluster";
38   	}
39   	
40   	static inline const char *
41   	when(void)
42   	{
43   	    return pcmk__is_set(controld_globals.fsa_input_register,
44   	                        R_SHUTDOWN)? " at shutdown" : "";
45   	}
46   	
47   	static void
48   	handle_attr_error(void)
49   	{
50   	    if (AM_I_DC) {
51   	        /* We are unable to provide accurate information to the
52   	         * scheduler, so allow another node to take over DC.
53   	         * @TODO Should we do this unconditionally on any failure?
54   	         */
55   	        crmd_exit(CRM_EX_FATAL);
56   	
57   	    } else if (pcmk__is_set(controld_globals.fsa_input_register, R_SHUTDOWN)) {
58   	        // Fast-track shutdown since unable to request via attribute
59   	        controld_fsa_append(C_FSA_INTERNAL, I_FAIL, NULL);
60   	    }
61   	}
62   	
63   	void
64   	update_attrd(const char *host, const char *name, const char *value,
65   	             bool is_remote_node)
66   	{
67   	    int rc = pcmk_rc_ok;
68   	
69   	    if (attrd_api == NULL) {
70   	        rc = pcmk_new_ipc_api(&attrd_api, pcmk_ipc_attrd);
71   	    }
72   	    if (rc == pcmk_rc_ok) {
73   	        uint32_t attrd_opts = pcmk__node_attr_value;
74   	
75   	        if (is_remote_node) {
76   	            pcmk__set_node_attr_flags(attrd_opts, pcmk__node_attr_remote);
77   	        }
78   	        rc = pcmk__attrd_api_update(attrd_api, host, name, value, NULL, NULL,
79   	                                    NULL, attrd_opts);
80   	    }
81   	    if (rc != pcmk_rc_ok) {
82   	        do_crm_log(AM_I_DC? LOG_CRIT : LOG_ERR,
83   	                   "Could not update attribute %s=%s for %s node %s%s: %s "
84   	                   QB_XS " rc=%d", name, value, node_type(is_remote_node),
85   	                   host, when(), pcmk_rc_str(rc), rc);
86   	        handle_attr_error();
87   	    }
88   	}
89   	
90   	void
91   	update_attrd_list(GList *attrs, uint32_t opts)
92   	{
93   	    int rc = pcmk_rc_ok;
94   	
95   	    if (attrd_api == NULL) {
96   	        rc = pcmk_new_ipc_api(&attrd_api, pcmk_ipc_attrd);
97   	    }
98   	    if (rc == pcmk_rc_ok) {
99   	        rc = pcmk__attrd_api_update_list(attrd_api, attrs, NULL, NULL, NULL,
100  	                                         opts | pcmk__node_attr_value);
101  	    }
102  	    if (rc != pcmk_rc_ok) {
103  	        do_crm_log(AM_I_DC? LOG_CRIT : LOG_ERR,
104  	                   "Could not update multiple node attributes: %s "
105  	                   QB_XS " rc=%d", pcmk_rc_str(rc), rc);
106  	        handle_attr_error();
107  	    }
108  	}
109  	
110  	/*!
111  	 * \internal
112  	 * \brief Ask attribute manager to purge a node and its transient attributes
113  	 *
114  	 * \param[in] node_name   Node to purge
115  	 * \param[in] from_cache  If true, purge from node caches as well
116  	 */
117  	void
118  	controld_purge_node_attrs(const char *node_name, bool from_cache)
119  	{
120  	    int rc = pcmk_rc_ok;
121  	
122  	    if (attrd_api == NULL) {
123  	        rc = pcmk_new_ipc_api(&attrd_api, pcmk_ipc_attrd);
124  	    }
125  	    if (rc == pcmk_rc_ok) {
126  	        pcmk__debug("Asking %s to purge transient attributes%s for %s",
127  	                    pcmk_ipc_name(attrd_api, true),
128  	                    (from_cache? " and node cache" : ""), node_name);
129  	        rc = pcmk__attrd_api_purge(attrd_api, node_name, from_cache);
130  	    }
131  	    if (rc != pcmk_rc_ok) {
132  	        pcmk__err("Could not purge node %s from %s%s: %s "
133  	                  QB_XS " rc=%d", node_name, pcmk_ipc_name(attrd_api, true),
134  	                  when(), pcmk_rc_str(rc), rc);
135  	    }
136  	}
137  	
138  	void
139  	update_attrd_clear_failures(const char *host, const char *rsc, const char *op,
140  	                            const char *interval_spec, gboolean is_remote_node)
141  	{
142  	    int rc = pcmk_rc_ok;
143  	
144  	    if (attrd_api == NULL) {
145  	        rc = pcmk_new_ipc_api(&attrd_api, pcmk_ipc_attrd);
146  	    }
147  	    if (rc == pcmk_rc_ok) {
148  	        uint32_t attrd_opts = pcmk__node_attr_none;
149  	
150  	        if (is_remote_node) {
151  	            pcmk__set_node_attr_flags(attrd_opts, pcmk__node_attr_remote);
152  	        }
153  	        rc = pcmk__attrd_api_clear_failures(attrd_api, host, rsc, op,
154  	                                            interval_spec, NULL, attrd_opts);
155  	    }
156  	    if (rc != pcmk_rc_ok) {
157  	        const char *interval_desc = "all";
158  	
159  	        if (op != NULL) {
160  	            interval_desc = pcmk__s(interval_spec, "nonrecurring");
161  	        }
162  	        pcmk__err("Could not clear failure of %s %s for %s on %s node %s%s: %s "
163  	                  QB_XS " rc=%d",
164  	                  interval_desc, pcmk__s(op, "operations"),
165  	                  pcmk__s(rsc, "all resources"), node_type(is_remote_node),
166  	                  host, when(), pcmk_rc_str(rc), rc);
167  	    }
168  	}
169