This source file includes following definitions.
- main
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11 #include <crm/crm.h>
12
13 #include <stdio.h>
14 #include <sys/types.h>
15 #include <unistd.h>
16
17 #include <stdlib.h>
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <libgen.h>
21 #include <glib.h>
22
23 #include <crm/common/xml.h>
24 #include <crm/common/util.h>
25 #include <crm/msg_xml.h>
26 #include <crm/cib.h>
27 #include <crm/pengine/status.h>
28 #include <pacemaker-internal.h>
29
30 gboolean USE_LIVE_CIB = FALSE;
31 char *cib_save = NULL;
32 extern gboolean stage0(pe_working_set_t * data_set);
33
34 static pcmk__cli_option_t long_options[] = {
35
36 {
37 "help", no_argument, NULL, '?',
38 "\tThis text", pcmk__option_default
39 },
40 {
41 "version", no_argument, NULL, '$',
42 "\tVersion information", pcmk__option_default
43 },
44 {
45 "verbose", no_argument, NULL, 'V',
46 "\tSpecify multiple times to increase debug output\n",
47 pcmk__option_default
48 },
49 {
50 "-spacer-", no_argument, NULL, '-',
51 "\nData sources:", pcmk__option_default
52 },
53 {
54 "live-check", no_argument, NULL, 'L',
55 "Check the configuration used by the running cluster\n",
56 pcmk__option_default
57 },
58 {
59 "xml-file", required_argument, NULL, 'x',
60 "Check the configuration in the named file", pcmk__option_default
61 },
62 {
63 "xml-text", required_argument, NULL, 'X',
64 "Check the configuration in the supplied string", pcmk__option_default
65 },
66 {
67 "xml-pipe", no_argument, NULL, 'p',
68 "Check the configuration piped in via stdin", pcmk__option_default
69 },
70 {
71 "-spacer-", no_argument, NULL, '-',
72 "\nAdditional Options:", pcmk__option_default
73 },
74 {
75 "save-xml", required_argument, 0, 'S',
76 "Save verified XML to named file (most useful with -L)",
77 pcmk__option_default
78 },
79 {
80 "-spacer-", no_argument, NULL, '-',
81 "\nExamples:", pcmk__option_paragraph
82 },
83 {
84 "-spacer-", no_argument, NULL, '-',
85 "Check the consistency of the configuration in the running cluster:",
86 pcmk__option_paragraph
87 },
88 {
89 "-spacer-", no_argument, NULL, '-',
90 " crm_verify --live-check", pcmk__option_example
91 },
92 {
93 "-spacer-", no_argument, NULL, '-',
94 "Check the consistency of the configuration in a given file and "
95 "produce verbose output:",
96 pcmk__option_paragraph
97 },
98 {
99 "-spacer-", no_argument, NULL, '-',
100 " crm_verify --xml-file file.xml --verbose", pcmk__option_example
101 },
102 {0, 0, 0, 0}
103 };
104
105 int
106 main(int argc, char **argv)
107 {
108 xmlNode *cib_object = NULL;
109 xmlNode *status = NULL;
110 int argerr = 0;
111 int flag;
112 int option_index = 0;
113
114 pe_working_set_t *data_set = NULL;
115 cib_t *cib_conn = NULL;
116 int rc = pcmk_ok;
117
118 bool verbose = FALSE;
119 gboolean xml_stdin = FALSE;
120 const char *xml_tag = NULL;
121 const char *xml_file = NULL;
122 const char *xml_string = NULL;
123
124 crm_log_cli_init("crm_verify");
125 pcmk__set_cli_options(NULL, "[options]", long_options,
126 "check a Pacemaker configuration for errors\n\n"
127 "Check the well-formedness of a complete Pacemaker "
128 "XML configuration,\nits conformance to the "
129 "configured schema, and the presence of common\n"
130 "misconfigurations. Problems reported as errors "
131 "must be fixed before the\ncluster will work "
132 "properly. It is left to the administrator to decide"
133 "\nwhether to fix problems reported as warnings.");
134
135 while (1) {
136 flag = pcmk__next_cli_option(argc, argv, &option_index, NULL);
137 if (flag == -1)
138 break;
139
140 switch (flag) {
141 case 'X':
142 crm_trace("Option %c => %s", flag, optarg);
143 xml_string = optarg;
144 break;
145 case 'x':
146 crm_trace("Option %c => %s", flag, optarg);
147 xml_file = optarg;
148 break;
149 case 'p':
150 xml_stdin = TRUE;
151 break;
152 case 'S':
153 cib_save = optarg;
154 break;
155 case 'V':
156 verbose = TRUE;
157 crm_bump_log_level(argc, argv);
158 break;
159 case 'L':
160 USE_LIVE_CIB = TRUE;
161 break;
162 case '$':
163 case '?':
164 pcmk__cli_help(flag, CRM_EX_OK);
165 break;
166 default:
167 fprintf(stderr, "Option -%c is not yet supported\n", flag);
168 ++argerr;
169 break;
170 }
171 }
172
173 if (optind < argc) {
174 printf("non-option ARGV-elements: ");
175 while (optind < argc) {
176 printf("%s ", argv[optind++]);
177 }
178 printf("\n");
179 }
180
181 if (optind > argc) {
182 ++argerr;
183 }
184
185 if (argerr) {
186 crm_err("%d errors in option parsing", argerr);
187 pcmk__cli_help(flag, CRM_EX_USAGE);
188 }
189
190 crm_info("=#=#=#=#= Getting XML =#=#=#=#=");
191
192 if (USE_LIVE_CIB) {
193 cib_conn = cib_new();
194 rc = cib_conn->cmds->signon(cib_conn, crm_system_name, cib_command);
195 }
196
197 if (USE_LIVE_CIB) {
198 if (rc == pcmk_ok) {
199 int options = cib_scope_local | cib_sync_call;
200
201 crm_info("Reading XML from: live cluster");
202 rc = cib_conn->cmds->query(cib_conn, NULL, &cib_object, options);
203 }
204
205 if (rc != pcmk_ok) {
206 fprintf(stderr, "Live CIB query failed: %s\n", pcmk_strerror(rc));
207 goto done;
208 }
209 if (cib_object == NULL) {
210 fprintf(stderr, "Live CIB query failed: empty result\n");
211 rc = -ENOMSG;
212 goto done;
213 }
214
215 } else if (xml_file != NULL) {
216 cib_object = filename2xml(xml_file);
217 if (cib_object == NULL) {
218 fprintf(stderr, "Couldn't parse input file: %s\n", xml_file);
219 rc = -ENODATA;
220 goto done;
221 }
222
223 } else if (xml_string != NULL) {
224 cib_object = string2xml(xml_string);
225 if (cib_object == NULL) {
226 fprintf(stderr, "Couldn't parse input string: %s\n", xml_string);
227 rc = -ENODATA;
228 goto done;
229 }
230 } else if (xml_stdin) {
231 cib_object = stdin2xml();
232 if (cib_object == NULL) {
233 fprintf(stderr, "Couldn't parse input from STDIN.\n");
234 rc = -ENODATA;
235 goto done;
236 }
237
238 } else {
239 fprintf(stderr, "No configuration source specified."
240 " Use --help for usage information.\n");
241 rc = -ENODATA;
242 goto done;
243 }
244
245 xml_tag = crm_element_name(cib_object);
246 if (!pcmk__str_eq(xml_tag, XML_TAG_CIB, pcmk__str_casei)) {
247 fprintf(stderr,
248 "This tool can only check complete configurations (i.e. those starting with <cib>).\n");
249 rc = -EBADMSG;
250 goto done;
251 }
252
253 if (cib_save != NULL) {
254 write_xml_file(cib_object, cib_save, FALSE);
255 }
256
257 status = get_object_root(XML_CIB_TAG_STATUS, cib_object);
258 if (status == NULL) {
259 create_xml_node(cib_object, XML_CIB_TAG_STATUS);
260 }
261
262 if (validate_xml(cib_object, NULL, FALSE) == FALSE) {
263 pcmk__config_err("CIB did not pass schema validation");
264 free_xml(cib_object);
265 cib_object = NULL;
266
267 } else if (cli_config_update(&cib_object, NULL, FALSE) == FALSE) {
268 pcmk__config_error = true;
269 free_xml(cib_object);
270 cib_object = NULL;
271 fprintf(stderr, "The cluster will NOT be able to use this configuration.\n");
272 fprintf(stderr, "Please manually update the configuration to conform to the %s syntax.\n",
273 xml_latest_schema());
274 }
275
276 data_set = pe_new_working_set();
277 if (data_set == NULL) {
278 rc = -errno;
279 crm_perror(LOG_CRIT, "Unable to allocate working set");
280 goto done;
281 }
282 pe__set_working_set_flags(data_set, pe_flag_no_counts|pe_flag_no_compat);
283
284 if (cib_object == NULL) {
285 } else if (status != NULL || USE_LIVE_CIB) {
286
287 pcmk__schedule_actions(data_set, cib_object, NULL);
288
289 } else {
290 data_set->now = crm_time_new(NULL);
291 data_set->input = cib_object;
292 stage0(data_set);
293 }
294 pe_free_working_set(data_set);
295
296 if (pcmk__config_error) {
297 fprintf(stderr, "Errors found during check: config not valid\n");
298 if (verbose == FALSE) {
299 fprintf(stderr, " -V may provide more details\n");
300 }
301 rc = -pcmk_err_schema_validation;
302
303 } else if (pcmk__config_warning) {
304 fprintf(stderr, "Warnings found during check: config may not be valid\n");
305 if (verbose == FALSE) {
306 fprintf(stderr, " Use -V -V for more details\n");
307 }
308 rc = -pcmk_err_schema_validation;
309 }
310
311 if (USE_LIVE_CIB && cib_conn) {
312 cib_conn->cmds->signoff(cib_conn);
313 cib_delete(cib_conn);
314 }
315
316 done:
317 crm_exit(crm_errno2exit(rc));
318 }