Exemple #1
0
/* 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;
}
Exemple #2
0
/* 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;
}
Exemple #3
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;
}
Exemple #4
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;
}