1 /*
2 * Copyright 2009-2020 the Pacemaker project contributors
3 *
4 * This source code is licensed under the GNU General Public License version 2
5 * or later (GPLv2+) WITHOUT ANY WARRANTY.
6 */
7
8 #include <stdint.h> // uint32_t, uint64_t
9 #include <crm/common/mainloop.h>
10
11 /*!
12 * \internal
13 * \brief Check to see if target was fenced in the last few seconds.
14 * \param tolerance, The number of seconds to look back in time
15 * \param target, The node to search for
16 * \param action, The action we want to match.
17 *
18 * \retval FALSE, not match
19 * \retval TRUE, fencing operation took place in the last 'tolerance' number of seconds.
20 */
21 gboolean stonith_check_fence_tolerance(int tolerance, const char *target, const char *action);
22
23 typedef struct stonith_device_s {
24 char *id;
25 char *agent;
26 char *namespace;
27
28 /*! list of actions that must execute on the target node. Used for unfencing */
29 char *on_target_actions;
30 GList *targets;
31 time_t targets_age;
32 gboolean has_attr_map;
33 /* should nodeid parameter for victim be included in agent arguments */
34 gboolean include_nodeid;
35 /* whether the cluster should automatically unfence nodes with the device */
36 gboolean automatic_unfencing;
37 guint priority;
38
39 uint32_t flags; // Group of enum st_device_flags
40
41 GHashTable *params;
42 GHashTable *aliases;
43 GList *pending_ops;
44 mainloop_timer_t *timer;
45 crm_trigger_t *work;
46 xmlNode *agent_metadata;
47
48 /*! A verified device is one that has contacted the
49 * agent successfully to perform a monitor operation */
50 gboolean verified;
51
52 gboolean cib_registered;
53 gboolean api_registered;
54 gboolean dirty;
55 } stonith_device_t;
56
57 /* These values are used to index certain arrays by "phase". Usually an
58 * operation has only one "phase", so phase is always zero. However, some
59 * reboots are remapped to "off" then "on", in which case "reboot" will be
60 * phase 0, "off" will be phase 1 and "on" will be phase 2.
61 */
62 enum st_remap_phase {
63 st_phase_requested = 0,
64 st_phase_off = 1,
65 st_phase_on = 2,
66 st_phase_max = 3
67 };
68
69 /* These values provide additional information for STONITH's asynchronous reply response.
70 * The st_reply_opt_merged value indicates an operation that has been merged and completed without being executed.
71 */
72 enum st_replay_option {
73 st_reply_opt_none = 0x00000000,
74 st_reply_opt_merged = 0x00000001,
75 };
76
77 typedef struct remote_fencing_op_s {
78 /* The unique id associated with this operation */
79 char *id;
80 /*! The node this operation will fence */
81 char *target;
82 /*! The fencing action to perform on the target. (reboot, on, off) */
83 char *action;
84
85 /*! When was the fencing action recorded (seconds since epoch) */
86 time_t created;
87
88 /*! Marks if the final notifications have been sent to local stonith clients. */
89 gboolean notify_sent;
90 /*! The number of query replies received */
91 guint replies;
92 /*! The number of query replies expected */
93 guint replies_expected;
94 /*! Does this node own control of this operation */
95 gboolean owner;
96 /*! After query is complete, This the high level timer that expires the entire operation */
97 guint op_timer_total;
98 /*! This timer expires the current fencing request. Many fencing
99 * requests may exist in a single operation */
100 guint op_timer_one;
101 /*! This timer expires the query request sent out to determine
102 * what nodes are contain what devices, and who those devices can fence */
103 guint query_timer;
104 /*! This is the default timeout to use for each fencing device if no
105 * custom timeout is received in the query. */
106 gint base_timeout;
107 /*! This is the calculated total timeout an operation can take before
108 * expiring. This is calculated by adding together all the timeout
109 * values associated with the devices this fencing operation may call */
110 gint total_timeout;
111
112 /*! Requested fencing delay.
113 * Value -1 means disable any static/random fencing delays. */
114 int delay;
115
116 /*! Delegate is the node being asked to perform a fencing action
117 * on behalf of the node that owns the remote operation. Some operations
118 * will involve multiple delegates. This value represents the final delegate
119 * that is used. */
120 char *delegate;
121 /*! The point at which the remote operation completed */
122 time_t completed;
123 //! Group of enum stonith_call_options associated with this operation
124 uint32_t call_options;
125
126 /*! The current state of the remote operation. This indicates
127 * what stage the op is in, query, exec, done, duplicate, failed. */
128 enum op_state state;
129 /*! The node that owns the remote operation */
130 char *originator;
131 /*! The local client id that initiated the fencing request */
132 char *client_id;
133 /*! The client's call_id that initiated the fencing request */
134 int client_callid;
135 /*! The name of client that initiated the fencing request */
136 char *client_name;
137 /*! List of the received query results for all the nodes in the cpg group */
138 GList *query_results;
139 /*! The original request that initiated the remote stonith operation */
140 xmlNode *request;
141
142 /*! The current topology level being executed */
143 guint level;
144 /*! The current operation phase being executed */
145 enum st_remap_phase phase;
146
147 /*! Devices with automatic unfencing (always run if "on" requested, never if remapped) */
148 GList *automatic_list;
149 /*! List of all devices at the currently executing topology level */
150 GList *devices_list;
151 /*! Current entry in the topology device list */
152 GList *devices;
153
154 /*! List of duplicate operations attached to this operation. Once this operation
155 * completes, the duplicate operations will be closed out as well. */
156 GList *duplicates;
157
158 } remote_fencing_op_t;
159
160 /*!
161 * \internal
162 * \brief Broadcast the result of an operation to the peers.
163 * \param op, Operation whose result should be broadcast
164 * \param rc, Result of the operation
165 */
166 void stonith_bcast_result_to_peers(remote_fencing_op_t * op, int rc, gboolean op_merged);
167
168 // Fencer-specific client flags
169 enum st_client_flags {
170 st_callback_unknown = UINT64_C(0),
171 st_callback_notify_fence = (UINT64_C(1) << 0),
172 st_callback_device_add = (UINT64_C(1) << 2),
173 st_callback_device_del = (UINT64_C(1) << 4),
174 st_callback_notify_history = (UINT64_C(1) << 5),
175 st_callback_notify_history_synced = (UINT64_C(1) << 6)
176 };
177
178 /*
179 * Complex fencing requirements are specified via fencing topologies.
180 * A topology consists of levels; each level is a list of fencing devices.
181 * Topologies are stored in a hash table by node name. When a node needs to be
182 * fenced, if it has an entry in the topology table, the levels are tried
183 * sequentially, and the devices in each level are tried sequentially.
184 * Fencing is considered successful as soon as any level succeeds;
185 * a level is considered successful if all its devices succeed.
186 * Essentially, all devices at a given level are "and-ed" and the
187 * levels are "or-ed".
188 *
189 * This structure is used for the topology table entries.
190 * Topology levels start from 1, so levels[0] is unused and always NULL.
191 */
192 typedef struct stonith_topology_s {
193 int kind;
194
195 /*! Node name regex or attribute name=value for which topology applies */
196 char *target;
197 char *target_value;
198 char *target_pattern;
199 char *target_attribute;
200
201 /*! Names of fencing devices at each topology level */
202 GList *levels[ST_LEVEL_MAX];
203
204 } stonith_topology_t;
205
206 void init_device_list(void);
207 void free_device_list(void);
208 void init_topology_list(void);
209 void free_topology_list(void);
210 void free_stonith_remote_op_list(void);
211 void init_stonith_remote_op_hash_table(GHashTable **table);
212 void free_metadata_cache(void);
213
214 uint64_t get_stonith_flag(const char *name);
215
216 void stonith_command(pcmk__client_t *client, uint32_t id, uint32_t flags,
217 xmlNode *op_request, const char *remote_peer);
218
219 int stonith_device_register(xmlNode * msg, const char **desc, gboolean from_cib);
220
221 int stonith_device_remove(const char *id, gboolean from_cib);
222
223 char *stonith_level_key(xmlNode * msg, int mode);
224 int stonith_level_kind(xmlNode * msg);
225 int stonith_level_register(xmlNode * msg, char **desc);
226
227 int stonith_level_remove(xmlNode * msg, char **desc);
228
229 stonith_topology_t *find_topology_for_host(const char *host);
230
231 void do_local_reply(xmlNode * notify_src, const char *client_id, gboolean sync_reply,
232 gboolean from_peer);
233
234 xmlNode *stonith_construct_reply(xmlNode * request, const char *output, xmlNode * data,
235 int rc);
236
237 void
238 do_stonith_async_timeout_update(const char *client, const char *call_id, int timeout);
239
240 void do_stonith_notify(int options, const char *type, int result, xmlNode * data);
241 void do_stonith_notify_device(int options, const char *op, int rc, const char *desc);
242 void do_stonith_notify_level(int options, const char *op, int rc, const char *desc);
243
244 remote_fencing_op_t *initiate_remote_stonith_op(pcmk__client_t *client,
245 xmlNode *request,
246 gboolean manual_ack);
247
248 int process_remote_stonith_exec(xmlNode * msg);
249
250 int process_remote_stonith_query(xmlNode * msg);
251
252 void *create_remote_stonith_op(const char *client, xmlNode * request, gboolean peer);
253
254 int stonith_fence_history(xmlNode *msg, xmlNode **output,
255 const char *remote_peer, int options);
256
257 void stonith_fence_history_trim(void);
258
259 bool fencing_peer_active(crm_node_t *peer);
260
261 int stonith_manual_ack(xmlNode * msg, remote_fencing_op_t * op);
262
263 gboolean string_in_list(GList *list, const char *item);
264
265 gboolean node_has_attr(const char *node, const char *name, const char *value);
266
267 extern char *stonith_our_uname;
268 extern gboolean stand_alone;
269 extern GHashTable *device_list;
270 extern GHashTable *topology;
271 extern long stonith_watchdog_timeout_ms;
272
273 extern GHashTable *stonith_remote_op_list;