Line data Source code
1 : /*
2 : * Copyright 2010-2024 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 Lesser General Public License
7 : * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8 : */
9 :
10 : #include <crm_internal.h>
11 :
12 : #ifndef _GNU_SOURCE
13 : # define _GNU_SOURCE
14 : #endif
15 :
16 : #include <sys/types.h>
17 : #include <sys/stat.h>
18 : #include <sys/wait.h>
19 : #include <errno.h>
20 : #include <unistd.h>
21 : #include <dirent.h>
22 : #include <grp.h>
23 : #include <string.h>
24 : #include <sys/time.h>
25 : #include <sys/resource.h>
26 :
27 : #include "crm/crm.h"
28 : #include <crm/common/xml.h>
29 : #include "crm/common/mainloop.h"
30 : #include "crm/services.h"
31 :
32 : #include "services_private.h"
33 : #include "services_nagios.h"
34 :
35 : /*!
36 : * \internal
37 : * \brief Prepare a Nagios action
38 : *
39 : * \param[in,out] op Action to prepare
40 : *
41 : * \return Standard Pacemaker return code
42 : */
43 : int
44 0 : services__nagios_prepare(svc_action_t *op)
45 : {
46 0 : op->opaque->exec = pcmk__full_path(op->agent, NAGIOS_PLUGIN_DIR);
47 0 : op->opaque->args[0] = strdup(op->opaque->exec);
48 0 : if (op->opaque->args[0] == NULL) {
49 0 : return ENOMEM;
50 : }
51 :
52 0 : if (pcmk__str_eq(op->action, PCMK_ACTION_MONITOR, pcmk__str_casei)
53 0 : && (op->interval_ms == 0)) {
54 :
55 : // Invoke --version for a nagios probe
56 0 : op->opaque->args[1] = strdup("--version");
57 0 : if (op->opaque->args[1] == NULL) {
58 0 : return ENOMEM;
59 : }
60 :
61 0 : } else if (op->params != NULL) {
62 : GHashTableIter iter;
63 0 : char *key = NULL;
64 0 : char *value = NULL;
65 0 : int index = 1; // 0 is already set to executable name
66 :
67 0 : g_hash_table_iter_init(&iter, op->params);
68 :
69 0 : while (g_hash_table_iter_next(&iter, (gpointer *) & key,
70 : (gpointer *) & value)) {
71 :
72 0 : if (index > (PCMK__NELEM(op->opaque->args) - 2)) {
73 0 : return E2BIG;
74 : }
75 :
76 0 : if (pcmk__str_eq(key, PCMK_XA_CRM_FEATURE_SET, pcmk__str_casei)
77 0 : || strstr(key, CRM_META "_")) {
78 0 : continue;
79 : }
80 :
81 0 : op->opaque->args[index++] = crm_strdup_printf("--%s", key);
82 0 : op->opaque->args[index++] = strdup(value);
83 0 : if (op->opaque->args[index - 1] == NULL) {
84 0 : return ENOMEM;
85 : }
86 : }
87 : }
88 :
89 : // Nagios actions don't need to keep the parameters
90 0 : if (op->params != NULL) {
91 0 : g_hash_table_destroy(op->params);
92 0 : op->params = NULL;
93 : }
94 0 : return pcmk_rc_ok;
95 : }
96 :
97 : /*!
98 : * \internal
99 : * \brief Map a Nagios result to a standard OCF result
100 : *
101 : * \param[in] exit_status Nagios exit status
102 : *
103 : * \return Standard OCF result
104 : */
105 : enum ocf_exitcode
106 0 : services__nagios2ocf(int exit_status)
107 : {
108 0 : switch (exit_status) {
109 0 : case NAGIOS_STATE_OK:
110 0 : return PCMK_OCF_OK;
111 :
112 0 : case NAGIOS_INSUFFICIENT_PRIV:
113 0 : return PCMK_OCF_INSUFFICIENT_PRIV;
114 :
115 0 : case NAGIOS_STATE_WARNING:
116 0 : return PCMK_OCF_DEGRADED;
117 :
118 0 : case NAGIOS_STATE_CRITICAL:
119 : case NAGIOS_STATE_UNKNOWN:
120 : default:
121 0 : return PCMK_OCF_UNKNOWN_ERROR;
122 : }
123 : }
124 :
125 : static inline char *
126 0 : nagios_metadata_name(const char *plugin)
127 : {
128 0 : return crm_strdup_printf(NAGIOS_METADATA_DIR "/%s.xml", plugin);
129 : }
130 :
131 : GList *
132 0 : services__list_nagios_agents(void)
133 : {
134 0 : GList *plugin_list = NULL;
135 0 : GList *result = NULL;
136 :
137 0 : plugin_list = services_os_get_directory_list(NAGIOS_PLUGIN_DIR, TRUE, TRUE);
138 :
139 : // Return only the plugins that have metadata
140 0 : for (GList *gIter = plugin_list; gIter != NULL; gIter = gIter->next) {
141 : struct stat st;
142 0 : const char *plugin = gIter->data;
143 0 : char *metadata = nagios_metadata_name(plugin);
144 :
145 0 : if (stat(metadata, &st) == 0) {
146 0 : result = g_list_append(result, strdup(plugin));
147 : }
148 0 : free(metadata);
149 : }
150 0 : g_list_free_full(plugin_list, free);
151 0 : return result;
152 : }
153 :
154 : gboolean
155 0 : services__nagios_agent_exists(const char *name)
156 : {
157 0 : char *buf = NULL;
158 0 : gboolean rc = FALSE;
159 : struct stat st;
160 :
161 0 : if (name == NULL) {
162 0 : return rc;
163 : }
164 :
165 0 : buf = crm_strdup_printf(NAGIOS_PLUGIN_DIR "/%s", name);
166 0 : if (stat(buf, &st) == 0) {
167 0 : rc = TRUE;
168 : }
169 :
170 0 : free(buf);
171 0 : return rc;
172 : }
173 :
174 : int
175 0 : services__get_nagios_metadata(const char *type, char **output)
176 : {
177 0 : int rc = pcmk_ok;
178 0 : FILE *file_strm = NULL;
179 0 : int start = 0, length = 0, read_len = 0;
180 0 : char *metadata_file = nagios_metadata_name(type);
181 :
182 0 : file_strm = fopen(metadata_file, "r");
183 0 : if (file_strm == NULL) {
184 0 : crm_err("Metadata file %s does not exist", metadata_file);
185 0 : free(metadata_file);
186 0 : return -EIO;
187 : }
188 :
189 : /* see how big the file is */
190 0 : start = ftell(file_strm);
191 0 : fseek(file_strm, 0L, SEEK_END);
192 0 : length = ftell(file_strm);
193 0 : fseek(file_strm, 0L, start);
194 :
195 0 : CRM_ASSERT(length >= 0);
196 0 : CRM_ASSERT(start == ftell(file_strm));
197 :
198 0 : if (length <= 0) {
199 0 : crm_info("%s was not valid", metadata_file);
200 0 : free(*output);
201 0 : *output = NULL;
202 0 : rc = -EIO;
203 :
204 : } else {
205 0 : crm_trace("Reading %d bytes from file", length);
206 0 : *output = pcmk__assert_alloc(1, (length + 1));
207 0 : read_len = fread(*output, 1, length, file_strm);
208 0 : if (read_len != length) {
209 0 : crm_err("Calculated and read bytes differ: %d vs. %d",
210 : length, read_len);
211 0 : free(*output);
212 0 : *output = NULL;
213 0 : rc = -EIO;
214 : }
215 : }
216 :
217 0 : fclose(file_strm);
218 0 : free(metadata_file);
219 0 : return rc;
220 : }
|