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