6 #include <sys/socket.h>
7 #include <netinet/in.h>
8 #include <netinet/tcp.h>
19 #include <sys/socket.h>
20 #include "lnetconfig/cyaml.h"
21 #include "lutf_listener.h"
22 #include "lutf_message.h"
23 #include "lutf_python.h"
32 lutf_help_usage(const struct option *long_options, const char *const description[])
36 fprintf(stderr, BOLDCYAN "LUTF Runs in two modes: "
37 RESET BOLDMAGENTA "Master" RESET BOLDCYAN " or " BOLDRED "Agent\n\n"
40 " . Runs on the Test Master node and controls all agents\n"
43 " . Runs on the Nodes Under Test\n\n"
45 "Look at lutf/python/config/lutf_cfg_sample.yaml for a sample "
46 "LUTF configuration\n\n"
50 while ((long_options[i].name != NULL) && (description[i] != NULL)) {
51 fprintf(stderr, "\t-%c or --%s %s\n",
52 (char) long_options[i].val,
58 fprintf(stderr, "\n");
61 static struct cYAML *get_value(struct cYAML *head, char *key)
63 struct cYAML *child = head;
65 while (child != NULL) {
66 if (strcmp(child->cy_string, key) == 0)
68 child = child->cy_next;
75 lutf_rc_t hostname_to_ip(char *hostname, char *ip, int len)
77 struct addrinfo hints, *servinfo, *p;
78 struct sockaddr_in *h;
81 memset(&hints, 0, sizeof(hints));
82 hints.ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6
83 hints.ai_socktype = SOCK_STREAM;
85 rv = getaddrinfo(hostname, "http", &hints, &servinfo);
87 PERROR("getaddrinfo: %s\n", gai_strerror(rv));
88 return EN_LUTF_RC_BAD_ADDR;
91 // loop through all the results and connect to the first we can
93 for (p = servinfo; p != NULL; p = p->ai_next) {
94 h = (struct sockaddr_in *) p->ai_addr;
95 strncpy(ip, inet_ntoa(h->sin_addr), len-1);
98 freeaddrinfo(servinfo); // all done with this structure
103 lutf_rc_t extract_config_parameters(struct cYAML *config_tree,
104 lutf_config_params_t *cfg,
113 head = config_tree->cy_child;
115 if (strcmp(head->cy_string, "lutf") != 0) {
117 return EN_LUTF_RC_BAD_PARAM;
120 /* go to the list of elements we need to browse */
121 head = head->cy_child;
123 tmp = get_value(head, "shell");
125 if (tmp->cy_type == CYAML_TYPE_STRING) {
126 if (strcmp(tmp->cy_valuestring,
128 cfg->shell = EN_LUTF_RUN_INTERACTIVE;
129 } else if (strcmp(tmp->cy_valuestring,
131 cfg->shell = EN_LUTF_RUN_BATCH;
132 } else if (strcmp(tmp->cy_valuestring,
134 cfg->shell = EN_LUTF_RUN_DAEMON;
137 return EN_LUTF_RC_BAD_PARAM;
141 return EN_LUTF_RC_BAD_PARAM;
145 return EN_LUTF_RC_MISSING_PARAM;
148 tmp = get_value(head, "agent");
150 if (tmp->cy_type == CYAML_TYPE_FALSE)
151 cfg->l_info.type = EN_LUTF_MASTER;
152 else if (tmp->cy_type == CYAML_TYPE_TRUE)
153 cfg->l_info.type = EN_LUTF_AGENT;
156 return EN_LUTF_RC_BAD_PARAM;
159 cfg->l_info.type = EN_LUTF_MASTER;
162 tmp = get_value(head, "telnet-port");
164 if (tmp->cy_type == CYAML_TYPE_NUMBER)
165 cfg->l_info.hb_info.agent_telnet_port = tmp->cy_valueint;
167 *elem = "telnet-port";
168 return EN_LUTF_RC_BAD_PARAM;
171 cfg->l_info.hb_info.agent_telnet_port = -1;
174 tmp = get_value(head, "master-address");
176 if (tmp->cy_type == CYAML_TYPE_STRING) {
177 if (!inet_aton(tmp->cy_valuestring, &addr)) {
178 /* maybe it's a host name so let's try
181 rc = hostname_to_ip(tmp->cy_valuestring, maddr,
183 if (rc != EN_LUTF_RC_OK) {
184 *elem = "master-address";
186 } else if (!inet_aton(maddr, &addr)) {
187 *elem = "master-address";
188 return EN_LUTF_RC_BAD_ADDR;
191 cfg->l_info.hb_info.master_address.sin_addr = addr;
193 *elem = "master-address";
194 return EN_LUTF_RC_BAD_PARAM;
196 } else if (cfg->l_info.type == EN_LUTF_AGENT) {
197 *elem = "master-address";
198 return EN_LUTF_RC_MISSING_PARAM;
201 tmp = get_value(head, "master-port");
203 if (tmp->cy_type == CYAML_TYPE_NUMBER) {
204 cfg->l_info.hb_info.master_address.sin_port = tmp->cy_valueint;
205 cfg->l_info.listen_port = tmp->cy_valueint;
207 *elem = "master-port";
208 return EN_LUTF_RC_BAD_PARAM;
211 cfg->l_info.hb_info.master_address.sin_port = DEFAULT_MASTER_PORT;
212 cfg->l_info.listen_port = DEFAULT_MASTER_PORT;
214 cfg->l_info.hb_info.master_address.sin_family = AF_INET;
216 tmp = get_value(head, "lutf-path");
218 if (tmp->cy_type == CYAML_TYPE_STRING)
219 cfg->lutf_path = tmp->cy_valuestring;
222 return EN_LUTF_RC_BAD_PARAM;
226 return EN_LUTF_RC_MISSING_PARAM;
229 tmp = get_value(head, "py-path");
231 if (tmp->cy_type == CYAML_TYPE_STRING)
232 cfg->py_path = tmp->cy_valuestring;
235 return EN_LUTF_RC_BAD_PARAM;
239 tmp = get_value(head, "node-name");
241 if (tmp->cy_type == CYAML_TYPE_STRING) {
242 strncpy(cfg->l_info.hb_info.node_name,
243 tmp->cy_valuestring, MAX_STR_LEN);
244 cfg->l_info.hb_info.node_name[MAX_STR_LEN - 1] = '\0';
247 return EN_LUTF_RC_BAD_PARAM;
250 strncpy(cfg->l_info.hb_info.node_name, TEST_ROLE_GRC,
252 cfg->l_info.hb_info.node_name[MAX_STR_LEN - 1] = '\0';
255 tmp = get_value(head, "master-name");
257 if (tmp->cy_type == CYAML_TYPE_STRING)
258 cfg->master_name = tmp->cy_valuestring;
260 return EN_LUTF_RC_BAD_PARAM;
261 } else if (cfg->l_info.type == EN_LUTF_AGENT) {
262 *elem = "master-name";
263 return EN_LUTF_RC_MISSING_PARAM;
266 tmp = get_value(head, "suite-list");
267 if (tmp && cfg->l_info.type == EN_LUTF_MASTER) {
268 if (tmp->cy_type == CYAML_TYPE_STRING)
269 if (strlen(tmp->cy_valuestring) > 0)
270 cfg->suite_list = tmp->cy_valuestring;
272 cfg->suite_list = NULL;
274 *elem = "suite-list";
275 return EN_LUTF_RC_BAD_PARAM;
279 tmp = get_value(head, "suite");
280 if (tmp && cfg->l_info.type == EN_LUTF_MASTER) {
281 if (tmp->cy_type == CYAML_TYPE_STRING)
282 if (strlen(tmp->cy_valuestring) > 0)
283 cfg->suite = tmp->cy_valuestring;
288 return EN_LUTF_RC_BAD_PARAM;
292 tmp = get_value(head, "script");
293 if (tmp && cfg->l_info.type == EN_LUTF_MASTER) {
294 if (tmp->cy_type == CYAML_TYPE_STRING)
295 if (strlen(tmp->cy_valuestring) > 0)
296 cfg->script = tmp->cy_valuestring;
301 return EN_LUTF_RC_BAD_PARAM;
305 if (!cfg->suite && cfg->script) {
307 return EN_LUTF_RC_BAD_PARAM;
310 tmp = get_value(head, "pattern");
312 if (tmp->cy_type == CYAML_TYPE_STRING)
313 if (strlen(tmp->cy_valuestring) > 0)
314 cfg->pattern = tmp->cy_valuestring;
319 return EN_LUTF_RC_BAD_PARAM;
325 tmp = get_value(head, "results");
327 if (tmp->cy_type == CYAML_TYPE_STRING)
328 cfg->results_file = tmp->cy_valuestring;
331 return EN_LUTF_RC_BAD_PARAM;
334 cfg->results_file = "/tmp/lutf/lutf_def_results";
337 tmp = get_value(head, "agent-list");
339 if (cYAML_is_sequence(tmp))
342 *elem = "agent-list";
343 return EN_LUTF_RC_BAD_PARAM;
349 tmp = get_value(head, "tmp-dir");
351 if (tmp->cy_type == CYAML_TYPE_STRING)
352 cfg->tmp_dir = tmp->cy_valuestring;
355 return EN_LUTF_RC_BAD_PARAM;
358 cfg->tmp_dir = "/tmp/lutf/";
361 return EN_LUTF_RC_OK;
365 main(int argc, char *argv[])
368 pthread_t l_thread_id;
371 char *config_file = NULL;
373 struct cYAML *config_tree;
374 struct cYAML *err_rc = NULL;
378 memset(&g_lutf_cfg, 0, sizeof(g_lutf_cfg));
380 /* If followed by a ':', the option requires an argument*/
381 const char *const short_options = "c:h";
382 const struct option long_options[] = {
383 {.name = "config", .has_arg = required_argument, .val = 'c'},
384 {.name = "help", .has_arg = no_argument, .val = 'h'},
388 static const char * const description[] = {
389 /*'c'*/":\n\t\tYAML config file",
390 /*'h'*/":\n\t\tPrint this help",
396 lutf_help_usage(long_options, description);
397 exit(LUTF_EXIT_ERR_STARTUP);
400 /*now process command line arguments*/
402 while ((cOpt = getopt_long(argc, argv,
408 config_file = optarg;
411 lutf_help_usage(long_options, description);
412 exit(LUTF_EXIT_NORMAL);
414 PERROR("Bad parameter");
415 exit(LUTF_EXIT_ERR_BAD_PARAM);
422 lutf_help_usage(long_options, description);
423 exit(LUTF_EXIT_ERR_BAD_PARAM);
426 g_lutf_cfg.cfg_path = config_file;
428 config_tree = cYAML_build_tree(config_file, NULL, 0, &err_rc, false);
430 PERROR("Failed to parse config file: %s", config_file);
431 exit(LUTF_EXIT_ERR_BAD_PARAM);
434 rc = extract_config_parameters(config_tree, &g_lutf_cfg, &elem);
435 if (rc != EN_LUTF_RC_OK) {
436 PERROR("Parsing configuration failed on %s with %s",
437 elem, lutf_rc2str(rc));
438 exit(LUTF_EXIT_ERR_BAD_PARAM);
441 outlog = calloc(strlen(g_lutf_cfg.tmp_dir) + strlen(OUT_LOG_NAME) + 2, 1);
444 PERROR("out of memory");
445 exit(LUTF_EXIT_ERR_STARTUP);
448 sprintf(outlog, "%s/%s", g_lutf_cfg.tmp_dir, OUT_LOG_NAME);
450 out = fopen(outlog, "w");
453 fprintf(stderr, "Failed to open log files: %s\n",
455 exit(LUTF_EXIT_ERR_STARTUP);
458 if (g_lutf_cfg.shell == EN_LUTF_RUN_DAEMON) {
459 pid_t process_id = 0;
462 /* create the child process */
464 if (process_id < 0) {
465 PERROR("Failed to run lutf as deamon");
466 exit(LUTF_EXIT_ERR_DEAMEON_STARTUP);
469 if (process_id > 0) {
471 * We're in the parent process so let's kill it
474 PDEBUG("Shutting down parent process");
475 exit(LUTF_EXIT_NORMAL);
481 PERROR("forking child failed");
482 exit(LUTF_EXIT_ERR_DEAMEON_STARTUP);
487 close(STDOUT_FILENO);
488 close(STDERR_FILENO);
490 PERROR("chdir failed");
491 exit(LUTF_EXIT_ERR_DEAMEON_STARTUP);
496 * Spawn the listener thread if we are in Master Mode.
497 * The listener thread listens for Heart beats and deals
498 * with maintaining the health of the agents. If an agent
499 * dies and comes back again, then we know how to deal
502 trc = pthread_create(&l_thread_id, NULL,
506 PERROR("Failed to start thread");
507 exit(LUTF_EXIT_ERR_THREAD_STARTUP);
510 /* spawn listener thread iff running in Master mode */
513 PERROR("Failed to initialize Python Module");
514 if (rc == EN_LUTF_RC_ERR_THREAD_STARTUP)
515 exit(LUTF_EXIT_ERR_THREAD_STARTUP);
517 exit(LUTF_EXIT_ERR_STARTUP);
520 pthread_join(l_thread_id, NULL);
524 cYAML_free_tree(config_tree);