/* Get info on a kb from any number of nodes. For all kbs, or all nodes, set the corresponding argument to NULL */ fsa_kb_info *fsaf_fetch_kb_info(const unsigned char *kb_name, fsa_node_addr *nodes) { fsa_node_addr *cur_node; int free_nodes = 0; /* free nodes if they werem't passed to function */ /* if no nodes given, get all nodes from config */ if (nodes == NULL) { fsa_error(LOG_DEBUG, "fetching kb info for all nodes"); GKeyFile *conf = fsa_get_config(); nodes = fsa_get_node_list(conf); fsa_config_free(conf); free_nodes = 1; } unsigned char *buf; unsigned char header_buf[ADM_HEADER_LEN]; /* store single header packet */ int nbytes, sock_fd, rv; struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; /* command to be sent to all stores */ int cmd_len; /* length of command packet */ unsigned char *cmd_pkt; /* command packet itself */ fsa_kb_info *ki_list = NULL; uint8_t cmdval; uint16_t datasize; char ipaddr[INET6_ADDRSTRLEN]; /* large enough to hold a v4 or v6 addr */ if (kb_name == NULL) { /* get info on all kbs */ fsa_error(LOG_DEBUG, "fetching info for all kbs"); cmd_pkt = fsap_encode_cmd_get_kb_info_all(&cmd_len); } else { /* request info on named kb */ fsa_error(LOG_DEBUG, "fetching info for kb '%s'", kb_name); cmd_pkt = fsap_encode_cmd_get_kb_info(kb_name, &cmd_len); } fsa_error(LOG_DEBUG, "admin command length is %d bytes", cmd_len); /* connect to each storage node */ for (cur_node = nodes; cur_node != NULL; cur_node = cur_node->next) { sock_fd = fsaf_connect_to_admind(cur_node->host, cur_node->port, &hints, ipaddr); if (sock_fd == -1) { fsa_error(LOG_ERR, "failed to connect to %s:%d, skipping node", cur_node->host, cur_node->port); continue; } /* send command to node */ nbytes = cmd_len; rv = fsa_sendall(sock_fd, cmd_pkt, &nbytes); if (rv == -1) { fsa_error(LOG_ERR, "failed to send command to %s:%d, skipping node", cur_node->host, cur_node->port); continue; } fsa_error(LOG_DEBUG, "header (%d bytes) sent to %s:%d, waiting for response", nbytes, cur_node->host, cur_node->port); /* get response header from node */ rv = fsa_fetch_header(sock_fd, header_buf); if (rv == -1) { fsa_error(LOG_ERR, "failed to get response from %s:%d, skipping node", cur_node->host, cur_node->port); continue; } fsa_error(LOG_DEBUG, "response received from %s:%d", cur_node->host, cur_node->port); /* server sent us data */ rv = fsap_decode_header(header_buf, &cmdval, &datasize); if (rv == -1) { fsa_error(LOG_ERR, "unable to decode header from %s:%d", cur_node->host, cur_node->port); close(sock_fd); continue; } /* alloc buffer for receiving further data into */ buf = (unsigned char *)malloc(datasize); if (buf == NULL) { errno = ENOMEM; free(cmd_pkt); return NULL; } fsa_error(LOG_DEBUG, "response header from %s:%d decoded", cur_node->host, cur_node->port); /* handle response from client */ if (cmdval == ADM_RSP_GET_KB_INFO_ALL) { fsa_error(LOG_DEBUG, "ADM_RSP_GET_KB_INFO_ALL received"); fsa_error(LOG_DEBUG, "fetching data from client"); nbytes = fsaf_recv_from_admind(sock_fd, buf, datasize); if (nbytes <= 0) { /* error already handled */ free(buf); continue; } /* local list of kb info for a single node */ fsa_kb_info *kid = fsap_decode_rsp_get_kb_info_all(buf); free(buf); fsa_kb_info *tmp_ki = NULL; fsa_kb_info *cur_ki = NULL; /* add kb info to list of info across nodes */ if (kid != NULL) { tmp_ki = kid; /* pointer to start of list */ cur_ki = kid; int done = 0; while (!done) { cur_ki->ipaddr = (unsigned char *)strdup(ipaddr); if (cur_ki->next == NULL) { /* if last item in list */ cur_ki->next = ki_list; /* append existing vals */ ki_list = tmp_ki; /* point to new head */ done = 1; } else { cur_ki = cur_ki->next; } } } } else if (cmdval == ADM_RSP_GET_KB_INFO) { fsa_error(LOG_DEBUG, "ADM_RSP_GET_KB_INFO_ALL received"); fsa_error(LOG_DEBUG, "fetching data from client"); nbytes = fsaf_recv_from_admind(sock_fd, buf, datasize); if (nbytes <= 0) { /* error already handled */ free(buf); continue; } fsa_kb_info *kid = fsap_decode_rsp_get_kb_info(buf); free(buf); if (kid != NULL) { /* copy ip addr to struct */ kid->ipaddr = (unsigned char *)strdup(ipaddr); kid->next = ki_list; ki_list = kid; } } close(sock_fd); } free(cmd_pkt); if (free_nodes) { fsa_node_addr_free(nodes); } return ki_list; }
/* Used to handle store starting/stopping, interface is mostly identical */ static int start_or_stop_stores(int action) { int all = 0; /* if -a flag, then start/stop all, instead of kb name */ int kb_name_len = 11; if (args_index < 0) { /* no argument given, display help text */ fsa_error( LOG_ERR, "No store name(s) given. Use `%s help %s' for details", program_invocation_short_name, argv[cmd_index] ); return 1; } if (strcmp("-a", argv[args_index]) == 0 || strcmp("--all", argv[args_index]) == 0) { all = 1; /* all stores */ } else { /* check for invalid store names */ for (int i = args_index; i < argc; i++) { if (!fsa_is_valid_kb_name(argv[i])) { fsa_error(LOG_ERR, "'%s' is not a valid store name", argv[i]); return 1; } int len = strlen(argv[i]); if (len > kb_name_len) { kb_name_len = len; } } } /* get list of all storage nodes */ fsa_node_addr *nodes = get_storage_nodes(); /* Setup hints information */ struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; int sock_fd, len; char ipaddr[INET6_ADDRSTRLEN]; unsigned char *buf; int node_num = 0; unsigned char *cmd = NULL; int n_errors = 0; /* to be set by fsa_send_recv_cmd */ int response, bufsize, err; int print_node_header = 1; int print_store_header = 1; for (fsa_node_addr *n = nodes; n != NULL; n = n->next) { sock_fd = fsaf_connect_to_admind(n->host, n->port, &hints, ipaddr); print_node_line(node_num, n->host, print_node_header); print_node_header = 0; node_num += 1; if (sock_fd == -1) { print_colour("unreachable\n", ANSI_COLOUR_RED); continue; } if (all) { /* start/stop all kbs */ if (action == STOP_STORE) { cmd = fsap_encode_cmd_stop_kb_all(&len); } else if (action == START_STORE) { cmd = fsap_encode_cmd_start_kb_all(&len); } if (cmd == NULL) { fsa_error(LOG_CRIT, "failed to encode %s command", argv[cmd_index]); n_errors += 1; break; } fsa_error(LOG_DEBUG, "sending '%s' command to %s:%d", argv[cmd_index], n->host, n->port); /* send command and get reply */ buf = fsaf_send_recv_cmd(n, sock_fd, cmd, len, &response, &bufsize, &err); /* usually a network error */ if (buf == NULL) { /* error already handled */ n_errors += 1; break; } /* should get this if all went well */ if (response == ADM_RSP_EXPECT_N_KB) { int rv; uint8_t rspval; uint16_t datasize; unsigned char header_buf[ADM_HEADER_LEN]; fsa_kb_response *kbr = NULL; int max_kb_len; int expected_responses = fsap_decode_rsp_expect_n_kb(buf, &max_kb_len); free(buf); fsa_error(LOG_DEBUG, "expecting %d responses from server", expected_responses); /* print header */ if (print_store_header) { if (colour_flag) { printf(ANSI_COLOUR_BLUE); } printf(" %-*s status\n", max_kb_len, "store_name"); if (colour_flag) { printf(ANSI_COLOUR_RESET); } } /* get packet from server for each kb started/stopped */ for (int i = 0; i < expected_responses; i++) { rv = fsa_fetch_header(sock_fd, header_buf); if (rv == -1) { fsa_error(LOG_ERR, "failed to get response from %s:%d", n->host, n->port); break; } fsa_error(LOG_DEBUG, "got header %d/%d", i+1, expected_responses); rv = fsap_decode_header(header_buf, &rspval, &datasize); if (rv == -1) { fsa_error(LOG_CRIT, "unable to decode header from %s:%d", n->host, n->port); break; } if (rspval == ADM_RSP_ABORT_EXPECT) { fsa_error(LOG_ERR, "operation aborted by server"); break; } buf = (unsigned char *)malloc(datasize); rv = fsaf_recv_from_admind(sock_fd, buf, datasize); if (rv < 0) { /* error already handled/logged */ free(buf); break; } if (rspval == ADM_RSP_STOP_KB) { kbr = fsap_decode_rsp_stop_kb(buf); printf(" %-*s ", max_kb_len, kbr->kb_name); switch (kbr->return_val) { case ADM_ERR_OK: case ADM_ERR_KB_STATUS_STOPPED: print_colour("stopped", ANSI_COLOUR_GREEN); break; case ADM_ERR_KB_STATUS_UNKNOWN: print_colour("unknown", ANSI_COLOUR_RED); break; default: fsa_error( LOG_CRIT, "Unknown server response: %d", kbr->return_val ); print_colour("unknown", ANSI_COLOUR_RED); break; } } else if (rspval == ADM_RSP_START_KB) { kbr = fsap_decode_rsp_start_kb(buf); printf(" %-*s ", max_kb_len, kbr->kb_name); switch (kbr->return_val) { case ADM_ERR_OK: case ADM_ERR_KB_STATUS_RUNNING: print_colour("running", ANSI_COLOUR_GREEN); break; case ADM_ERR_KB_STATUS_STOPPED: print_colour("stopped", ANSI_COLOUR_YELLOW); break; case ADM_ERR_KB_STATUS_UNKNOWN: print_colour("unknown", ANSI_COLOUR_RED); break; default: fsa_error( LOG_CRIT, "Unknown server response: %d", kbr->return_val ); print_colour("unknown", ANSI_COLOUR_RED); break; } } printf("\n"); free(buf); buf = NULL; fsa_kb_response_free(kbr); kbr = NULL; } } else if (response == ADM_RSP_ERROR) { unsigned char *errmsg = fsap_decode_rsp_error(buf, bufsize); fsa_error(LOG_ERR, "server error: %s", errmsg); free(errmsg); free(buf); } else { fsa_error(LOG_ERR, "unexpected response from server: %d", response); free(buf); } } else { /* print header */ if (print_store_header) { if (colour_flag) { printf(ANSI_COLOUR_BLUE); } printf(" %-*s status\n", kb_name_len, "store_name"); if (colour_flag) { printf(ANSI_COLOUR_RESET); } print_store_header = 0; } /* stop kbs given on command line */ for (int i = args_index; i < argc; i++) { /* send start/stop command for each kb */ if (action == STOP_STORE) { cmd = fsap_encode_cmd_stop_kb((unsigned char *)argv[i], &len); } else if (action == START_STORE) { cmd = fsap_encode_cmd_start_kb((unsigned char *)argv[i], &len); } if (cmd == NULL) { fsa_error(LOG_CRIT, "failed to encode %s command", argv[cmd_index]); n_errors += 1; break; } fsa_error(LOG_DEBUG, "sending %s '%s' command to %s:%d", argv[cmd_index], argv[i], n->host, n->port); buf = fsaf_send_recv_cmd(n, sock_fd, cmd, len, &response, &bufsize, &err); free(cmd); cmd = NULL; /* usually a network error */ if (buf == NULL) { /* error already handled */ n_errors += 1; break; } printf(" %-*s ", kb_name_len, argv[i]); fsa_kb_response *kbr = NULL; if (response == ADM_RSP_STOP_KB) { kbr = fsap_decode_rsp_stop_kb(buf); switch (kbr->return_val) { case ADM_ERR_OK: case ADM_ERR_KB_STATUS_STOPPED: print_colour("stopped", ANSI_COLOUR_GREEN); break; case ADM_ERR_KB_NOT_EXISTS: print_colour("store_not_found", ANSI_COLOUR_RED); break; default: print_colour("unknown", ANSI_COLOUR_RED); break; } printf("\n"); fsa_kb_response_free(kbr); } else if (response == ADM_RSP_START_KB) { kbr = fsap_decode_rsp_start_kb(buf); switch (kbr->return_val) { case ADM_ERR_OK: case ADM_ERR_KB_STATUS_RUNNING: print_colour("running", ANSI_COLOUR_GREEN); break; case ADM_ERR_KB_STATUS_STOPPED: print_colour("stopped", ANSI_COLOUR_YELLOW); break; case ADM_ERR_KB_NOT_EXISTS: print_colour("store_not_found", ANSI_COLOUR_RED); break; default: print_colour("unknown", ANSI_COLOUR_RED); break; } printf("\n"); fsa_kb_response_free(kbr); } else if (response == ADM_RSP_ERROR) { unsigned char *msg = fsap_decode_rsp_error(buf, bufsize); printf("unknown: %s\n", msg); free(msg); n_errors += 1; } else { fsa_error(LOG_CRIT, "unknown response from server"); n_errors += 1; } free(buf); } } /* done with current server */ close(sock_fd); } if (n_errors > 0) { return 1; } return 0; }
static int cmd_delete_stores(void) { if (args_index < 0) { /* no argument given, display help text */ fsa_error( LOG_ERR, "No store name(s) given. Use `%s help %s' for details", program_invocation_short_name, argv[cmd_index] ); return 1; } /* check for invalid store names */ int store_name_len = 11; for (int i = args_index; i < argc; i++) { if (!fsa_is_valid_kb_name(argv[i])) { fsa_error(LOG_ERR, "'%s' is not a valid store name", argv[i]); return 1; } int len = strlen(argv[i]); if (len > store_name_len) { store_name_len = len; } } /* get list of all storage nodes */ fsa_node_addr *node; fsa_node_addr *nodes = get_storage_nodes(); int n_nodes = 0; int node_name_len = 9; for (node = nodes; node != NULL; node = node->next) { int len = strlen(node->host); if (len > node_name_len) { node_name_len = len; } n_nodes += 1; } /* connections to each node */ int *sock_fds = init_sock_fds(n_nodes); /* Setup hints information */ struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; char ipaddr[INET6_ADDRSTRLEN]; int cur_node = 0; int print_node_header = 1; int node_status; printf("Checking cluster status:\n"); for (fsa_node_addr *n = nodes; n != NULL; n = n->next) { sock_fds[cur_node] = fsaf_connect_to_admind(n->host, n->port, &hints, ipaddr); if (sock_fds[cur_node] == -1) { node_status = -1; } else { node_status = 0; } print_node_status_line(cur_node, n->host, node_status, node_name_len, print_node_header); print_node_header = 0; cur_node += 1; } /* check that we've got a connection to all nodes */ for (int i = 0; i < n_nodes; i++) { if (sock_fds[i] == -1) { cleanup_sock_fds(sock_fds, n_nodes); printf("Failed to connect to all nodes, aborting.\n"); return 1; } } printf("\n"); int response, bufsize, err, len; int n_errors = 0; int n_deleted; unsigned char *cmd; unsigned char *buf; int print_store_header = 1; /* delete one kb at a time across all nodes */ for (int i = args_index; i < argc; i++) { cur_node = 0; n_deleted = 0; cmd = fsap_encode_cmd_delete_kb((unsigned char *)argv[i], &len); if (cmd == NULL) { fsa_error(LOG_CRIT, "failed to encode %s command", argv[cmd_index]); n_errors += 1; break; } for (node = nodes; node != NULL; node = node->next) { fsa_error(LOG_DEBUG, "sending %s '%s' command to %s:%d", argv[cmd_index], argv[i], node->host, node->port); buf = fsaf_send_recv_cmd(node, sock_fds[cur_node], cmd, len, &response, &bufsize, &err); /* usually a network error */ if (buf == NULL) { /* error already handled */ n_errors += 1; break; } if (response == ADM_RSP_DELETE_KB) { fsa_kb_response *kbr = fsap_decode_rsp_delete_kb(buf); switch (kbr->return_val) { case ADM_ERR_OK: fsa_error( LOG_DEBUG, "kb '%s' deleted on node %s", kbr->kb_name, node->host ); n_deleted += 1; break; case ADM_ERR_KB_STATUS_UNKNOWN: /* kb deleted, but runtime status not confirmed */ fsa_error( LOG_DEBUG, "kb '%s' deleted on node %s, but runtime status " "not confirmed", kbr->kb_name, node->host ); n_deleted += 1; break; case ADM_ERR_KB_NOT_EXISTS: fsa_error( LOG_DEBUG, "kb '%s' does not exist on node %s", kbr->kb_name, node->host ); break; case ADM_ERR_KB_GET_INFO: fsa_error( LOG_ERR, "failed to get info for kb '%s' on node %s", kbr->kb_name, node->host ); n_errors += 1; break; case ADM_ERR_POPEN: case ADM_ERR_GENERIC: default: fsa_error( LOG_ERR, "failed to delete kb '%s' on node %s", kbr->kb_name, node->host ); n_errors += 1; break; } fsa_kb_response_free(kbr); } else if (response == ADM_RSP_ERROR) { unsigned char *errmsg = fsap_decode_rsp_error(buf, bufsize); fsa_error(LOG_ERR, "server error: %s", errmsg); free(errmsg); free(buf); n_errors += 1; break; } else { fsa_error(LOG_CRIT, "unknown response from server"); free(buf); n_errors += 1; break; } free(buf); if (n_errors > 0) { break; } cur_node += 1; } free(cmd); if (n_errors > 0) { break; } if (print_store_header) { if (colour_flag) { printf(ANSI_COLOUR_BLUE); } printf("%-*s store_status\n", store_name_len, "store_name"); if (colour_flag) { printf(ANSI_COLOUR_RESET); } print_store_header = 0; } printf("%-*s ", store_name_len, argv[i]); /* else kb deleted on all nodes */ if (n_deleted == 0) { print_colour("store_not_found\n", ANSI_COLOUR_YELLOW); } else { print_colour("deleted\n", ANSI_COLOUR_GREEN); } } /* cleanup */ cleanup_sock_fds(sock_fds, n_nodes); if (n_errors > 0) { printf( "An error occurred while deleting stores, check status manually\n" ); return 1; } return 0; }
/* Check whether admin daemon on all nodes is reachable */ static int cmd_list_nodes(void) { /* this command has no arguments, exit if any are found */ if (args_index >= 0) { print_invalid_arg(); return 1; } /* network related vars */ struct addrinfo hints; int default_port = FS_ADMIND_PORT; fsa_node_addr *nodes = NULL; fsa_node_addr *p; int sock_fd; char ipaddr[INET6_ADDRSTRLEN]; /* printing/output related vars */ int all_nodes_ok = 0; int hostlen = 13; int len; int node_num = 0; int n_nodes = 0; /* Setup hints information */ memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; /* attempt to read /etc/4store.conf */ GKeyFile *config = fsa_get_config(); if (config == NULL) { /* assume localhost if no config file found */ fsa_error(LOG_WARNING, "Unable to read config file at '%s', assuming localhost\n", fs_get_config_file()); } else { nodes = fsa_get_node_list(config); if (nodes == NULL) { fsa_error(LOG_WARNING, "No nodes found in '%s', assuming localhost\n", fs_get_config_file()); default_port = fsa_get_admind_port(config); } } if (nodes == NULL) { /* Use localhost and default port */ nodes = fsa_node_addr_new("localhost"); nodes->port = default_port; } /* loop through once to get lengths of various fields */ for (p = nodes; p != NULL; p = p->next) { len = strlen(p->host) + 1; if (len > hostlen) { hostlen = len; } n_nodes += 1; } int n_nodes_len = int_len(n_nodes); if (n_nodes_len < 11) { n_nodes_len = 11; } /* print column headers */ if (colour_flag) { printf(ANSI_COLOUR_BLUE); } printf("%-*s %-*s port status ip_address\n", n_nodes_len, "node_number", hostlen, "hostname"); if (colour_flag) { printf(ANSI_COLOUR_RESET); } /* loop through all nodes and attempt to connect admin daemon on each */ for (p = nodes; p != NULL; p = p->next) { /* set default output for IP address */ strcpy(ipaddr, "unknown"); /* check if we can open conn to admin daemon */ sock_fd = fsaf_connect_to_admind(p->host, p->port, &hints, ipaddr); /* print result of attempted connection */ printf("%-*d %-*s %-5d ", n_nodes_len, node_num, hostlen, p->host, p->port); if (sock_fd == -1) { print_colour("unreachable", ANSI_COLOUR_RED); all_nodes_ok = 2; } else { print_colour("ok ", ANSI_COLOUR_GREEN); close(sock_fd); } printf(" %s\n", ipaddr); node_num += 1; } fsa_node_addr_free(nodes); fsa_config_free(config); return all_nodes_ok; }