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"
28 struct in_addr g_local_ip;
32 /*externs needed by getopt lib*/
37 lutf_help_usage(const struct option *long_options, const char *description[])
41 fprintf(stderr, BOLDCYAN "LUTF Runs in two modes: "
42 RESET BOLDMAGENTA "Master" RESET BOLDCYAN " or " BOLDRED "Agent\n\n"
45 " . Runs on the Test Master node and controls all agents\n"
48 " . Runs on the Nodes Under Test\n\n"
50 "Look at lutf/python/config/lutf_cfg_sample.yaml for a sample "
51 "LUTF configuration\n\n"
55 while ((long_options[i].name != NULL) && (description[i] != NULL)) {
56 fprintf(stderr, "\t-%c or --%s %s\n",
57 (char) long_options[i].val,
63 fprintf(stderr, "\n");
66 static struct cYAML *get_value(struct cYAML *head, char *key)
68 struct cYAML *child = head;
70 while (child != NULL) {
71 if (strcmp(child->cy_string, key) == 0)
73 child = child->cy_next;
80 lutf_rc_t hostname_to_ip(char *hostname, char *ip, int len)
82 struct addrinfo hints, *servinfo, *p;
83 struct sockaddr_in *h;
86 memset(&hints, 0, sizeof(hints));
87 hints.ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6
88 hints.ai_socktype = SOCK_STREAM;
90 if ((rv = getaddrinfo(hostname, "http", &hints, &servinfo)) != 0) {
91 PERROR("getaddrinfo: %s\n", gai_strerror(rv));
92 return EN_LUTF_RC_BAD_ADDR;
95 // loop through all the results and connect to the first we can
97 for (p = servinfo; p != NULL; p = p->ai_next) {
98 h = (struct sockaddr_in *) p->ai_addr;
99 strncpy(ip, inet_ntoa(h->sin_addr), len-1);
102 freeaddrinfo(servinfo); // all done with this structure
103 return EN_LUTF_RC_OK;
107 lutf_rc_t extract_config_parameters(struct cYAML *config_tree,
108 lutf_config_params_t *cfg,
117 head = config_tree->cy_child;
119 if (strcmp(head->cy_string, "lutf") != 0) {
121 return EN_LUTF_RC_BAD_PARAM;
124 /* go to the list of elements we need to browse */
125 head = head->cy_child;
127 tmp = get_value(head, "shell");
129 if (tmp->cy_type == CYAML_TYPE_STRING) {
130 if (strcmp(tmp->cy_valuestring,
132 cfg->shell = EN_LUTF_RUN_INTERACTIVE;
133 } else if (strcmp(tmp->cy_valuestring,
135 cfg->shell = EN_LUTF_RUN_BATCH;
136 } else if (strcmp(tmp->cy_valuestring,
138 cfg->shell = EN_LUTF_RUN_DAEMON;
141 return EN_LUTF_RC_BAD_PARAM;
145 return EN_LUTF_RC_BAD_PARAM;
149 return EN_LUTF_RC_MISSING_PARAM;
152 tmp = get_value(head, "agent");
154 if (tmp->cy_type == CYAML_TYPE_FALSE)
155 cfg->l_info.type = EN_LUTF_MASTER;
156 else if (tmp->cy_type == CYAML_TYPE_TRUE)
157 cfg->l_info.type = EN_LUTF_AGENT;
160 return EN_LUTF_RC_BAD_PARAM;
163 cfg->l_info.type = EN_LUTF_MASTER;
166 tmp = get_value(head, "telnet-port");
168 if (tmp->cy_type == CYAML_TYPE_NUMBER)
169 cfg->l_info.hb_info.agent_telnet_port = tmp->cy_valueint;
171 *elem = "telnet-port";
172 return EN_LUTF_RC_BAD_PARAM;
175 cfg->l_info.hb_info.agent_telnet_port = -1;
178 tmp = get_value(head, "master-address");
180 if (tmp->cy_type == CYAML_TYPE_STRING) {
181 if (!inet_aton(tmp->cy_valuestring, &addr)) {
182 /* maybe it's a host name so let's try
185 rc = EN_LUTF_RC_BAD_ADDR;
186 if ((rc = hostname_to_ip(tmp->cy_valuestring, maddr,
189 *elem = "master-address";
191 } else if (!inet_aton(maddr, &addr)) {
192 *elem = "master-address";
196 cfg->l_info.hb_info.master_address.sin_addr = addr;
198 *elem = "master-address";
199 return EN_LUTF_RC_BAD_PARAM;
201 } else if (cfg->l_info.type == EN_LUTF_AGENT) {
202 *elem = "master-address";
203 return EN_LUTF_RC_MISSING_PARAM;
206 tmp = get_value(head, "master-port");
208 if (tmp->cy_type == CYAML_TYPE_NUMBER) {
209 cfg->l_info.hb_info.master_address.sin_port = tmp->cy_valueint;
210 cfg->l_info.listen_port = tmp->cy_valueint;
212 *elem = "master-port";
213 return EN_LUTF_RC_BAD_PARAM;
216 cfg->l_info.hb_info.master_address.sin_port = DEFAULT_MASTER_PORT;
217 cfg->l_info.listen_port = DEFAULT_MASTER_PORT;
219 cfg->l_info.hb_info.master_address.sin_family = AF_INET;
221 tmp = get_value(head, "lutf-path");
223 if (tmp->cy_type == CYAML_TYPE_STRING)
224 cfg->lutf_path = tmp->cy_valuestring;
227 return EN_LUTF_RC_BAD_PARAM;
231 return EN_LUTF_RC_MISSING_PARAM;
234 tmp = get_value(head, "py-path");
236 if (tmp->cy_type == CYAML_TYPE_STRING)
237 cfg->py_path = tmp->cy_valuestring;
240 return EN_LUTF_RC_BAD_PARAM;
244 tmp = get_value(head, "node-name");
246 if (tmp->cy_type == CYAML_TYPE_STRING) {
247 strncpy(cfg->l_info.hb_info.node_name, tmp->cy_valuestring,
249 cfg->l_info.hb_info.node_name[MAX_STR_LEN - 1] = '\0';
252 return EN_LUTF_RC_BAD_PARAM;
255 strncpy(cfg->l_info.hb_info.node_name, TEST_ROLE_GRC,
257 cfg->l_info.hb_info.node_name[MAX_STR_LEN - 1] = '\0';
260 tmp = get_value(head, "master-name");
262 if (tmp->cy_type == CYAML_TYPE_STRING)
263 cfg->master_name = tmp->cy_valuestring;
265 return EN_LUTF_RC_BAD_PARAM;
266 } else if (cfg->l_info.type == EN_LUTF_AGENT) {
267 *elem = "master-name";
268 return EN_LUTF_RC_MISSING_PARAM;
271 tmp = get_value(head, "suite");
272 if (tmp && cfg->l_info.type == EN_LUTF_MASTER) {
273 if (tmp->cy_type == CYAML_TYPE_STRING)
274 if (strlen(tmp->cy_valuestring) > 0)
275 cfg->suite = tmp->cy_valuestring;
280 return EN_LUTF_RC_BAD_PARAM;
284 tmp = get_value(head, "script");
285 if (tmp && cfg->l_info.type == EN_LUTF_MASTER) {
286 if (tmp->cy_type == CYAML_TYPE_STRING)
287 if (strlen(tmp->cy_valuestring) > 0)
288 cfg->script = tmp->cy_valuestring;
293 return EN_LUTF_RC_BAD_PARAM;
297 if (!cfg->suite && cfg->script) {
299 return EN_LUTF_RC_BAD_PARAM;
302 tmp = get_value(head, "pattern");
304 if (tmp->cy_type == CYAML_TYPE_STRING)
305 if (strlen(tmp->cy_valuestring) > 0)
306 cfg->pattern = tmp->cy_valuestring;
311 return EN_LUTF_RC_BAD_PARAM;
317 tmp = get_value(head, "results");
319 if (tmp->cy_type == CYAML_TYPE_STRING)
320 cfg->results_file = tmp->cy_valuestring;
323 return EN_LUTF_RC_BAD_PARAM;
326 cfg->results_file = "lutf_def_results";
329 tmp = get_value(head, "agent-list");
331 if (cYAML_is_sequence(tmp))
334 *elem = "agent-list";
335 return EN_LUTF_RC_BAD_PARAM;
341 tmp = get_value(head, "tmp-dir");
343 if (tmp->cy_type == CYAML_TYPE_STRING)
344 cfg->tmp_dir = tmp->cy_valuestring;
347 return EN_LUTF_RC_BAD_PARAM;
350 cfg->tmp_dir = "/tmp/lutf/";
353 return EN_LUTF_RC_OK;
357 main(int argc, char *argv[])
360 pthread_t l_thread_id;
363 char *config_file = NULL;
365 struct cYAML *config_tree;
366 struct cYAML *err_rc = NULL;
370 memset(&g_lutf_cfg, 0, sizeof(g_lutf_cfg));
372 /* If followed by a ':', the option requires an argument*/
373 const char *const short_options = "c:h";
374 const struct option long_options[] = {
375 {.name = "config", .has_arg = required_argument, .val = 'c'},
376 {.name = "help", .has_arg = no_argument, .val = 'h'},
380 const char *description[] = {
381 /*'c'*/":\n\t\tYAML config file",
382 /*'h'*/":\n\t\tPrint this help",
388 lutf_help_usage(long_options, description);
389 exit(LUTF_EXIT_ERR_STARTUP);
392 /*now process command line arguments*/
394 while ((cOpt = getopt_long(argc, argv,
400 config_file = optarg;
403 lutf_help_usage(long_options, description);
404 exit(LUTF_EXIT_NORMAL);
406 PERROR("Bad parameter");
407 exit(LUTF_EXIT_ERR_BAD_PARAM);
414 lutf_help_usage(long_options, description);
415 exit(LUTF_EXIT_ERR_BAD_PARAM);
418 g_lutf_cfg.cfg_path = config_file;
420 config_tree = cYAML_build_tree(config_file, NULL, 0, &err_rc, false);
422 PERROR("Failed to parse config file: %s", config_file);
423 exit(LUTF_EXIT_ERR_BAD_PARAM);
426 rc = extract_config_parameters(config_tree, &g_lutf_cfg, &elem);
427 if (rc != EN_LUTF_RC_OK) {
428 PERROR("Parsing configuration failed on %s with %s",
429 elem, lutf_rc2str(rc));
430 exit(LUTF_EXIT_ERR_BAD_PARAM);
433 outlog = calloc(strlen(g_lutf_cfg.tmp_dir) + strlen(OUT_LOG_NAME) + 2, 1);
436 PERROR("out of memory");
437 exit(LUTF_EXIT_ERR_STARTUP);
440 sprintf(outlog, "%s/%s", g_lutf_cfg.tmp_dir, OUT_LOG_NAME);
442 out = fopen(outlog, "w");
445 fprintf(stderr, "Failed to open log files: %s\n",
447 exit(LUTF_EXIT_ERR_STARTUP);
450 if (g_lutf_cfg.shell == EN_LUTF_RUN_DAEMON) {
451 pid_t process_id = 0;
454 /* create the child process */
456 if (process_id < 0) {
457 PERROR("Failed to run lutf as deamon");
458 exit(LUTF_EXIT_ERR_DEAMEON_STARTUP);
461 if (process_id > 0) {
463 * We're in the parent process so let's kill it
466 PDEBUG("Shutting down parent process");
467 exit(LUTF_EXIT_NORMAL);
473 PERROR("forking child failed");
474 exit(LUTF_EXIT_ERR_DEAMEON_STARTUP);
479 close(STDOUT_FILENO);
480 close(STDERR_FILENO);
482 PERROR("chdir failed");
483 exit(LUTF_EXIT_ERR_DEAMEON_STARTUP);
488 * Spawn the listener thread if we are in Master Mode.
489 * The listener thread listens for Heart beats and deals
490 * with maintaining the health of the agents. If an agent
491 * dies and comes back again, then we know how to deal
494 trc = pthread_create(&l_thread_id, NULL,
498 PERROR("Failed to start thread");
499 exit(LUTF_EXIT_ERR_THREAD_STARTUP);
502 /* spawn listener thread iff running in Master mode */
505 PERROR("Failed to initialize Python Module");
506 if (rc == EN_LUTF_RC_ERR_THREAD_STARTUP)
507 exit(LUTF_EXIT_ERR_THREAD_STARTUP);
509 exit(LUTF_EXIT_ERR_STARTUP);
512 pthread_join(l_thread_id, NULL);
516 cYAML_free_tree(config_tree);