X-Git-Url: http://andersk.mit.edu/gitweb/moira.git/blobdiff_plain/faef095447f6ce055a6b848b72a54a1268a760de..255443e811e1ad7ef82d5be1b20af4aa5a8b2a11:/clients/moira/cluster.c diff --git a/clients/moira/cluster.c b/clients/moira/cluster.c index d6299d34..157e3874 100644 --- a/clients/moira/cluster.c +++ b/clients/moira/cluster.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "defs.h" #include "f_defs.h" @@ -40,23 +41,35 @@ #include void PrintAliases(char **info); +static void PrintMachine(char **info); struct mqelem *GetMCInfo(int type, char *name1, char *name2); +struct mqelem *GetMachineByOwner(char *type, char *name); char **AskMCDInfo(char **info, int type, Bool name); int CheckAndRemoveFromCluster(char *name, Bool ask_user); +int CheckAndRemoveCnames(char *name, Bool ask_user); int CheckAndRemoveMachines(char *name, Bool ask_first); -#define MACHINE 0 -#define CLUSTER 1 -#define DATA 2 -#define MAP 3 -#define SUBNET 4 -#define CNAME 5 +static char *PrintContainerInfo(char **info); +static void RealUpdateContainer(char **info, Bool junk); +static void RealDeleteContainer(char **info, Bool one_container); +static void RealRemoveMachineFromContainer(char **info, Bool one_contmap); + +#define MACHINE 0 +#define CLUSTER 1 +#define DATA 2 +#define MAP 3 +#define SUBNET 4 +#define CNAME 5 +#define CONTAINER 6 +#define CONTMAP 7 #define M_DEFAULT_TYPE DEFAULT_NONE #define C_DEFAULT_DESCRIPT DEFAULT_NONE #define C_DEFAULT_LOCATION DEFAULT_NONE +#define CON_DEFAULT_TYPE DEFAULT_NONE + #define CD_DEFAULT_LABEL DEFAULT_NONE #define CD_DEFAULT_DATA DEFAULT_NONE @@ -70,6 +83,14 @@ static char *states[] = { "Deleted (3)" }; +static char *subnet_states[] = { + "Reserved (0)", + "Billable (1)", + "Private (2)", + "Resnet (3)", + "Infrastructure (4)" +}; + static char *MacState(int state) { static char buf[BUFSIZ]; @@ -82,7 +103,17 @@ static char *MacState(int state) return states[state]; } +static char *SubnetState(int state) +{ + static char buf[BUFSIZ]; + if (state < 0 || state > 4) + { + sprintf(buf, "Unknown (%d)", state); + return buf; + } + return subnet_states[state]; +} /* -------------------- Set Defaults -------------------- */ @@ -101,6 +132,8 @@ static char **SetMachineDefaults(char **info, char *name) info[M_OS] = strdup(M_DEFAULT_TYPE); info[M_LOC] = strdup(M_DEFAULT_TYPE); info[M_CONTACT] = strdup(M_DEFAULT_TYPE); + info[M_BILL_CONTACT] = strdup(M_DEFAULT_TYPE); + info[M_ACCT_NUMBER] = strdup(""); info[M_USE] = strdup("0"); info[M_STAT] = strdup("1"); info[M_SUBNET] = strdup("NONE"); @@ -109,7 +142,7 @@ static char **SetMachineDefaults(char **info, char *name) info[M_OWNER_NAME] = strdup("NONE"); info[M_ACOMMENT] = strdup(""); info[M_OCOMMENT] = strdup(""); - info[15] = info[16] = NULL; + info[17] = info[18] = NULL; return info; } @@ -129,6 +162,21 @@ static char **SetClusterDefaults(char **info, char *name) return info; } +static char **SetContainerDefaults(char **info, char *name) +{ + info[CON_NAME] = strdup(name); + info[CON_DESCRIPT] = strdup(CON_DEFAULT_TYPE); + info[CON_LOCATION] = strdup(CON_DEFAULT_TYPE); + info[CON_CONTACT] = strdup(CON_DEFAULT_TYPE); + info[CON_OWNER_TYPE] = strdup("NONE"); + info[CON_OWNER_NAME] = strdup("NONE"); + info[CON_MEMACE_TYPE] = strdup("NONE"); + info[CON_MEMACE_NAME] = strdup("NONE"); + info[CON_MODBY] = info[CON_MODTIME] = info[CON_MODWITH] = NULL; + info[CON_END] = NULL; + return info; +} + /* Function Name: SetSubnetDefaults * Description: sets Subnet defaults. * Arguments: info - an array to put the defaults into. @@ -140,8 +188,11 @@ static char **SetSubnetDefaults(char **info, char *name) { char buf[256]; - info[C_NAME] = strdup(name); + info[SN_NAME] = strdup(name); info[SN_DESC] = strdup(""); + info[SN_STATUS] = strdup("1"); + info[SN_CONTACT] = strdup(DEFAULT_NONE); + info[SN_ACCT_NUMBER] = strdup(""); sprintf(buf, "%ld", ntohl(inet_addr("18.255.0.0"))); info[SN_ADDRESS] = strdup(buf); sprintf(buf, "%ld", ntohl(inet_addr("255.255.0.0"))); @@ -215,14 +266,20 @@ static char *PrintMachInfo(char **info) MacState(atoi(info[M_STAT])), info[M_STAT_CHNG]); Put_message(buf); Put_message(""); - - sprintf(buf, "Vendor: %-16s Model: %-20s OS: %s", - info[M_VENDOR], info[M_MODEL], info[M_OS]); + sprintf(buf, "Vendor: %-16s Location: %s", info[M_VENDOR], + info[M_LOC]); + Put_message(buf); + sprintf(buf, "Model: %-16s Contact: %s", info[M_MODEL], + info[M_CONTACT]); + Put_message(buf); + sprintf(buf, "OS: %-16s Billing Contact: %s", info[M_OS], + info[M_BILL_CONTACT]); Put_message(buf); - sprintf(buf, "Location: %-16s Contact: %-20s Opt: %s", - info[M_LOC], info[M_CONTACT], info[M_USE]); + sprintf(buf, "Opt: %-16s Account Number: %s", info[M_USE], + info[M_ACCT_NUMBER]); Put_message(buf); - sprintf(buf, "\nAdm cmt: %s", info[M_ACOMMENT]); + Put_message(""); + sprintf(buf, "Adm cmt: %s", info[M_ACOMMENT]); Put_message(buf); sprintf(buf, "Op cmt: %s", info[M_OCOMMENT]); Put_message(buf); @@ -231,9 +288,39 @@ static char *PrintMachInfo(char **info) Put_message(buf); sprintf(buf, MOD_FORMAT, info[M_MODBY], info[M_MODTIME], info[M_MODWITH]); Put_message(buf); + /* Do a get_subnet for the machine's subnet. We need to know if it's + * Private. + */ + args[0] = info[M_SUBNET]; + stat = do_mr_query("get_subnet", 1, args, StoreInfo, &elem); + if (stat) + com_err(program_name, stat, " looking up subnet info"); + if (atoi(((char **)elem->q_data)[2]) == SNET_STATUS_PRIVATE) + { + Put_message(""); + sprintf(buf, "Warning: This host is on a private subnet."); + Put_message(buf); + sprintf(buf, "Billing information shown is superceded by billing information for the subnet."); + Put_message(buf); + } + return info[M_NAME]; } +/* Function Name: PrintMachine + * Description: Prints the name of a machine record + * Arguments: info - array of information about the machine. + * Returns: nothing. + */ + +static void PrintMachine(char **info) +{ + char buf[BUFSIZ]; + + sprintf(buf, "Machine: %s", info[M_NAME]); + Put_message(buf); +} + /* Function Name: PrintCname * Description: Prints the Data on a host alias * Arguments: info a pointer to the data array. @@ -321,6 +408,12 @@ static char *PrintSubnetInfo(char **info) Put_message(buf); sprintf(buf, " Description: %s", info[SN_DESC]); Put_message(buf); + sprintf(buf, " Status: %s", SubnetState(atoi(info[SN_STATUS]))); + Put_message(buf); + sprintf(buf, " Contact: %s", info[SN_CONTACT]); + Put_message(buf); + sprintf(buf, " Account Number: %s", info[SN_ACCT_NUMBER]); + Put_message(buf); addr.s_addr = htonl(atoi(info[SN_ADDRESS])); mask.s_addr = htonl(atoi(info[SN_MASK])); low.s_addr = htonl(atoi(info[SN_LOW])); @@ -425,6 +518,23 @@ struct mqelem *GetMCInfo(int type, char *name1, char *name2) com_err(program_name, stat, " in get_cluster_data."); return NULL; } + break; + case CONTAINER: + args[CON_NAME] = name1; + if ((stat = do_mr_query("get_container", 1, &name1, StoreInfo, &elem))) + { + com_err(program_name, stat, " in get_container."); + return NULL; + } + break; + case CONTMAP: + args[0] = name1; + if ((stat = do_mr_query("get_machine_to_container_map", 1, &name1, + StoreInfo, &elem))) + { + com_err(program_name, stat, " in get_machine_to_container_map."); + return NULL; + } } return QueueTop(elem); } @@ -436,6 +546,7 @@ struct mqelem *GetMCInfo(int type, char *name1, char *name2) * type - type of information - MACHINE * CLUSTER * DATA + * CONTAINER * name - T/F : change the name of this type. * Returns: none. */ @@ -462,6 +573,10 @@ char **AskMCDInfo(char **info, int type, Bool name) sprintf(temp_buf, "Setting the Data for the Cluster %s...", info[CD_NAME]); break; + case CONTAINER: + sprintf(temp_buf, "Setting the Data for the Container %s...", + info[CON_NAME]); + break; } Put_message(temp_buf); @@ -496,6 +611,12 @@ char **AskMCDInfo(char **info, int type, Bool name) SUB_ERROR) return NULL; break; + case CONTAINER: + newname = strdup(info[CON_NAME]); + if (GetValueFromUser("The new name for this container? ", &newname) + == SUB_ERROR) + return NULL; + break; default: Put_message("Unknown type in AskMCDInfo, programmer botch"); return NULL; @@ -517,6 +638,12 @@ char **AskMCDInfo(char **info, int type, Bool name) if (GetValueFromUser("Machine's contact", &info[M_CONTACT]) == SUB_ERROR) return NULL; + if (GetValueFromUser("Machine's billing contact", + &info[M_BILL_CONTACT]) == SUB_ERROR) + return NULL; + if (GetValueFromUser("Machine's billing account number", + &info[M_ACCT_NUMBER]) == SUB_ERROR) + return NULL; while (1) { int i; @@ -541,49 +668,76 @@ char **AskMCDInfo(char **info, int type, Bool name) if (name) { /* info did not come from SetMachineDefaults(), which does not - * initialize entry 8 (M_STAT_CHNG), therefore we can + * initialize entry 10 (M_STAT_CHNG), therefore we can * free it. */ /* This is an update of an existing machine and the structure * was filled in thru a query to the db which does fill in this * field. */ - free(info[8]); + free(info[10]); } - info[8] = info[M_SUBNET]; - info[9] = info[M_ADDR]; - info[10] = info[M_OWNER_TYPE]; - info[11] = info[M_OWNER_NAME]; - info[12] = info[M_ACOMMENT]; - info[13] = info[M_OCOMMENT]; + info[10] = info[M_SUBNET]; + info[11] = info[M_ADDR]; + info[12] = info[M_OWNER_TYPE]; + info[13] = info[M_OWNER_NAME]; + info[14] = info[M_ACOMMENT]; + info[15] = info[M_OCOMMENT]; if (name) { - if (GetValueFromUser("Machine's network (or 'none')", &info[8]) + if (GetValueFromUser("Machine's network (or 'none')", &info[10]) == SUB_ERROR) return NULL; } if (GetValueFromUser("Machine's address (or 'unassigned' or 'unique')", - &info[9]) == SUB_ERROR) + &info[11]) == SUB_ERROR) return NULL; - if (GetTypeFromUser("Machine's owner type", "ace_type", &info[10]) == + if (GetTypeFromUser("Machine's owner type", "ace_type", &info[12]) == SUB_ERROR) return NULL; - if (strcmp(info[10], "NONE") && - GetValueFromUser("Owner's Name", &info[11]) == SUB_ERROR) + if (strcmp(info[12], "NONE") && + GetValueFromUser("Owner's Name", &info[13]) == SUB_ERROR) return NULL; - if (GetValueFromUser("Administrative comment", &info[12]) == SUB_ERROR) + if (!strcmp(info[12], "KERBEROS")) + { + char *canon; + + mrcl_validate_kerberos_member(info[13], &canon); + if (mrcl_get_message()) + Put_message(mrcl_get_message()); + free(info[13]); + info[13] = canon; + } + if (GetValueFromUser("Administrative comment", &info[14]) == SUB_ERROR) return NULL; - if (GetValueFromUser("Operational comment", &info[13]) == SUB_ERROR) + if (GetValueFromUser("Operational comment", &info[15]) == SUB_ERROR) return NULL; - info[14] = NULL; - FreeAndClear(&info[15], TRUE); - FreeAndClear(&info[16], TRUE); + info[16] = NULL; + FreeAndClear(&info[17], TRUE); + FreeAndClear(&info[18], TRUE); break; case SUBNET: if (GetValueFromUser("Network description", &info[SN_DESC]) == SUB_ERROR) return NULL; + while (1) + { + int i; + if (GetValueFromUser("Network's status (? for help)", + &info[SN_STATUS]) == SUB_ERROR) + return NULL; + if (isdigit(info[SN_STATUS][0])) + break; + Put_message("Valid status numbers:"); + for (i = 0; i < 5; i++) + Put_message(subnet_states[i]); + } + if (GetValueFromUser("Network's contact", &info[SN_CONTACT]) == SUB_ERROR) + return NULL; + if (GetValueFromUser("Network's billing account number", + &info[SN_ACCT_NUMBER]) == SUB_ERROR) + return NULL; if (GetAddressFromUser("Network address", &info[SN_ADDRESS]) == SUB_ERROR) return NULL; if (GetAddressFromUser("Network mask", &info[SN_MASK]) == SUB_ERROR) @@ -628,6 +782,16 @@ char **AskMCDInfo(char **info, int type, Bool name) if (strcmp(info[SN_ACE_TYPE], "NONE") && GetValueFromUser("Owner name", &info[SN_ACE_NAME]) == SUB_ERROR) return NULL; + if (!strcmp(info[SN_ACE_TYPE], "KERBEROS")) + { + char *canon; + + mrcl_validate_kerberos_member(info[SN_ACE_NAME], &canon); + if (mrcl_get_message()) + Put_message(mrcl_get_message()); + free(info[SN_ACE_NAME]); + info[SN_ACE_NAME] = canon; + } FreeAndClear(&info[SN_MODTIME], TRUE); FreeAndClear(&info[SN_MODBY], TRUE); FreeAndClear(&info[SN_MODWITH], TRUE); @@ -650,6 +814,53 @@ char **AskMCDInfo(char **info, int type, Bool name) if (GetValueFromUser("The data itself ? ", &info[CD_DATA]) == SUB_ERROR) return NULL; break; + case CONTAINER: + if (GetValueFromUser("Container's Description:", &info[CON_DESCRIPT]) == + SUB_ERROR) + return NULL; + if (GetValueFromUser("Container's Location:", &info[CON_LOCATION]) == + SUB_ERROR) + return NULL; + if (GetValueFromUser("Container's Contact:", &info[CON_CONTACT]) == + SUB_ERROR) + return NULL; + if (GetTypeFromUser("Container's owner type", "ace_type", + &info[CON_OWNER_TYPE]) == SUB_ERROR) + return NULL; + if (strcmp(info[CON_OWNER_TYPE], "NONE") && + GetValueFromUser("Owner's Name", &info[CON_OWNER_NAME]) == SUB_ERROR) + return NULL; + if (!strcmp(info[CON_OWNER_TYPE], "KERBEROS")) + { + char *canon; + + mrcl_validate_kerberos_member(info[CON_OWNER_NAME], &canon); + if (mrcl_get_message()) + Put_message(mrcl_get_message()); + free(info[CON_OWNER_NAME]); + info[CON_OWNER_NAME] = canon; + } + if (GetTypeFromUser("Container's Membership ACL", "ace_type", + &info[CON_MEMACE_TYPE]) == SUB_ERROR) + return NULL; + if (strcmp(info[CON_MEMACE_TYPE], "NONE") && + GetValueFromUser("Membership ACL", &info[CON_MEMACE_NAME]) + == SUB_ERROR) + return NULL; + if (!strcmp(info[CON_MEMACE_TYPE], "KERBEROS")) + { + char *canon; + + mrcl_validate_kerberos_member(info[CON_MEMACE_NAME], &canon); + if (mrcl_get_message()) + Put_message(mrcl_get_message()); + free(info[CON_MEMACE_NAME]); + info[CON_MEMACE_NAME] = canon; + } + FreeAndClear(&info[CON_MODTIME], TRUE); + FreeAndClear(&info[CON_MODBY], TRUE); + FreeAndClear(&info[CON_MODWITH], TRUE); + break; } /* @@ -862,7 +1073,7 @@ int UpdateMachine(int argc, char **argv) /* Function Name: CheckAndRemoveFromCluster * Description: This func tests to see if a machine is in a cluster. * and if so then removes it - * Arguments: name - name of the machine (already Canonocalized). + * Arguments: name - name of the machine (already Canonicalized). * ask_user- query the user before removing if from clusters? * Returns: MR_ERROR if machine left in a cluster, or mr_error. */ @@ -927,6 +1138,73 @@ int CheckAndRemoveFromCluster(char *name, Bool ask_user) return ret_value; } +/* Function Name: CheckAndRemoveCnames + * Description: This func tests to see if a machine has cnames, + * and if so then removes them. + * Arguments: name - name of the machine (already Canonicalized). + * ask_user- query the user before removing cnames? + * Returns: MR_ERROR if machine left with a cname, or mr_error. + */ + +int CheckAndRemoveCnames(char *name, Bool ask_user) +{ + int stat, ret_value; + Bool delete_it; + char *args[10], temp_buf[BUFSIZ], *ptr; + struct mqelem *top, *elem = NULL; + + ret_value = SUB_NORMAL; + args[0] = "*"; + args[1] = name; + stat = do_mr_query("get_hostalias", 2, args, StoreInfo, &elem); + if (stat && stat != MR_NO_MATCH) + { + com_err(program_name, stat, " in get_hostalias."); + return DM_NORMAL; + } + if (stat == MR_SUCCESS) + { + elem = top = QueueTop(elem); + if (ask_user) + { + sprintf(temp_buf, "%s has the following cnames.", name); + Put_message(temp_buf); + Loop(top, (void (*)(char **)) PrintCname); + ptr = "Remove ** ALL ** these cnames?"; + if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */ + delete_it = TRUE; + else + { + Put_message("Aborting..."); + FreeQueue(top); + return SUB_ERROR; + } + } + else + delete_it = TRUE; + + if (delete_it) + { + while (elem) + { + char **info = elem->q_data; + if ((stat = do_mr_query("delete_hostalias", 2, info, + NULL, NULL))) + { + ret_value = SUB_ERROR; + com_err(program_name, stat, " in delete_hostalias."); + sprintf(temp_buf, + "Cname %s ** NOT ** removed from host %s.", + info[0], info[1]); + Put_message(temp_buf); + } + elem = elem->q_forw; + } + } + } + return ret_value; +} + /* Function Name: RealDeleteMachine * Description: Actually Deletes the Machine. * Arguments: info - nescessary information stored as an array of char *'s @@ -946,18 +1224,21 @@ static void RealDeleteMachine(char **info, Bool one_machine) { if (CheckAndRemoveFromCluster(info[M_NAME], TRUE) != SUB_ERROR) { - if ((stat = do_mr_query("delete_host", 1, - &info[M_NAME], NULL, NULL))) - { - com_err(program_name, stat, " in DeleteMachine."); - sprintf(temp_buf, "%s ** NOT ** deleted.", - info[M_NAME]); - Put_message(temp_buf); - } - else + if (CheckAndRemoveCnames(info[M_NAME], TRUE) != SUB_ERROR) { - sprintf(temp_buf, "%s successfully Deleted.", info[M_NAME]); - Put_message(temp_buf); + if ((stat = do_mr_query("delete_host", 1, + &info[M_NAME], NULL, NULL))) + { + com_err(program_name, stat, " in DeleteMachine."); + sprintf(temp_buf, "%s ** NOT ** deleted.", + info[M_NAME]); + Put_message(temp_buf); + } + else + { + sprintf(temp_buf, "%s successfully Deleted.", info[M_NAME]); + Put_message(temp_buf); + } } } } @@ -1177,7 +1458,7 @@ static void RealRemoveMachineFromCluster(char **info, Bool one_map) int RemoveMachineFromCluster(int argc, char **argv) { struct mqelem *elem = NULL; - char buf[BUFSIZ], * args[10]; + char buf[BUFSIZ], *args[10]; int stat; args[MAP_MACHINE] = canonicalize_hostname(strdup(argv[1])); @@ -1194,7 +1475,7 @@ int RemoveMachineFromCluster(int argc, char **argv) StoreInfo, &elem); if (stat == MR_NO_MATCH) { - sprintf(buf, "The machine %s is not is the cluster %s.", + sprintf(buf, "The machine %s is not in the cluster %s.", args[MAP_MACHINE], args[MAP_CLUSTER]); Put_message(buf); free(args[MAP_MACHINE]); @@ -1630,8 +1911,16 @@ int ShowClusterData(int argc, char **argv) int AddClusterData(int argc, char **argv) { - int stat; + int stat, i; + for (i = 1; i < 4; i++) + { + if (IS_EMPTY(argv[i])) + { + Put_message("Cluster data cannot be an empty string."); + return DM_NORMAL; + } + } if ((stat = do_mr_query("add_cluster_data", 3, argv + 1, NULL, NULL))) com_err(program_name, stat, " in AddClusterData."); return DM_NORMAL; @@ -1719,3 +2008,542 @@ int MachineToClusterMap(int argc, char **argv) free(tmpname); return DM_NORMAL; } + +/* Function Name: MachineByOwner + * Description: This function prints all machines which are owned by + * a given user or group. + * Arguments: none. + * Returns: DM_NORMAL. + */ + +int MachineByOwner(int argc, char **argv) +{ + char buf[BUFSIZ], temp_buf[BUFSIZ], *type, *name; + struct mqelem *top; + + type = strdup("USER"); + if (GetTypeFromUser("Type of owner", "ace_type", &type) == SUB_ERROR) + return DM_NORMAL; + + sprintf(buf, "Name of %s", type); + name = strdup(user); + if (GetValueFromUser(buf, &name) == SUB_ERROR) + return DM_NORMAL; + + switch (YesNoQuestion("Do you want a recursive search (y/n)", FALSE)) + { + case TRUE: + sprintf(temp_buf, "R%s", type); /* "USER to "RUSER", etc. */ + free(type); + type = strdup(temp_buf); + break; + case FALSE: + break; + default: + return DM_NORMAL; + } + + top = GetMachineByOwner(type, name); + Loop(top, PrintMachine); + + FreeQueue(top); + return DM_NORMAL; +} + +/* Function Name: GetMachineByOwner + * Description: This function stores information retrieved by + * the get_host_by_owner query + * Arguments: type - an ace_type, argv[0] for the query + * name - name of machine, argv[1] for the query + * Returns: the top element of a queue returning the data, or NULL. + */ + +struct mqelem *GetMachineByOwner(char *type, char *name) +{ + char *args[2]; + struct mqelem *elem = NULL; + int status; + + args[0] = type; + args[1] = name; + if ((status = do_mr_query("get_host_by_owner", 2, args, StoreInfo, &elem))) + { + com_err(program_name, status, " in get_host_by_owner"); + return NULL; + } + return QueueTop(elem); +} + +int MachineByAcctNumber(int argc, char **argv) +{ + char *args[0], *account_number; + int status; + struct mqelem *elem = NULL; + + if (GetValueFromUser("Account Number", &account_number) == SUB_ERROR) + return DM_NORMAL; + + args[0] = account_number; + if (status = do_mr_query("get_host_by_account_number", 1, args, StoreInfo, + &elem)) + { + com_err(program_name, status, " in get_host_by_account_number"); + return DM_NORMAL; + } + Loop(QueueTop(elem), (void (*)(char **)) PrintMachInfo); + FreeQueue(elem); + + return DM_NORMAL; +} + +int ShowContainerInfo(int argc, char **argv) +{ + struct mqelem *top; + + top = GetMCInfo(CONTAINER, argv[1], NULL); + Loop(top, (void (*)(char **)) PrintContainerInfo); + FreeQueue(top); + return DM_NORMAL; +} + +static char *PrintContainerInfo(char **info) +{ + char buf[BUFSIZ], tbuf[256]; + + Put_message(""); + sprintf(buf, "Container: %-16s", info[CON_NAME]); + Put_message(buf); + sprintf(buf, "Description: %-16s", info[CON_DESCRIPT]); + Put_message(buf); + sprintf(buf, "Location: %-16s Contact: %s", info[CON_LOCATION], + info[CON_CONTACT]); + Put_message(buf); + sprintf(tbuf, "%s %s", info[CON_OWNER_TYPE], + strcmp(info[CON_OWNER_TYPE], "NONE") ? info[CON_OWNER_NAME] : ""); + sprintf(buf, "Owner: %-16s", tbuf); + Put_message(buf); + sprintf(tbuf, "%s %s", info[CON_MEMACE_TYPE], + strcmp(info[CON_MEMACE_TYPE], "NONE") ? info[CON_MEMACE_NAME] : ""); + sprintf(buf, "Membership ACL: %-16s", tbuf); + Put_message(buf); + Put_message(""); + sprintf(buf, MOD_FORMAT, info[CON_MODBY], info[CON_MODTIME], + info[CON_MODWITH]); + Put_message(buf); + return info[CON_NAME]; +} + +static char *PrintContainer(char **info) +{ + char buf[BUFSIZ]; + + sprintf(buf, "Container: %s", info[CON_NAME]); + Put_message(buf); +} + +static char *PrintMContMap(char **info) +{ + char buf[BUFSIZ]; + sprintf(buf, "Container: %-30s Machine: %-20s", + info[1], info[0]); + Put_message(buf); + return ""; +} + +int AddContainer(int argc, char **argv) +{ + char **args, *info[MAX_ARGS_SIZE], *name = argv[1]; + int stat; + + /* Can't use ValidName() because spaces are allowed in container names */ + if (IS_EMPTY(name)) + { + Put_message("Please use a non-empty name."); + return DM_NORMAL; + } + + if (strchr(name, '*') || strchr(name, '?')) + { + Put_message("Wildcards not accepted here."); + return DM_NORMAL; + } + + /* Check if this cluster already exists. */ + if ((stat = do_mr_query("get_container", 1, &name, NULL, NULL)) + == MR_SUCCESS) + { + Put_message("This container already exists."); + return DM_NORMAL; + } + else if (stat != MR_NO_MATCH) + { + com_err(program_name, stat, " in AddContainer."); + return DM_NORMAL; + } + if (!(args = AskMCDInfo(SetContainerDefaults(info, name), CONTAINER, FALSE))) + { + Put_message("Aborted."); + FreeInfo(info); + return DM_NORMAL; + } + + /* Create the new container. */ + if ((stat = do_mr_query("add_container", CountArgs(args), args, NULL, NULL))) + com_err(program_name, stat, " in AddContainer."); + + FreeInfo(info); + return DM_NORMAL; +} + +int UpdateContainer(int argc, char **argv) +{ + struct mqelem *top; + top = GetMCInfo(CONTAINER, argv[1], NULL); + QueryLoop(top, NullPrint, RealUpdateContainer, "Update the container"); + + FreeQueue(top); + return DM_NORMAL; +} + +static void RealUpdateContainer(char **info, Bool junk) +{ + int stat; + char **args = AskMCDInfo(info, CONTAINER, TRUE); + + if (!args) + { + Put_message("Aborted."); + return; + } + if ((stat = do_mr_query("update_container", CountArgs(args), args, + NULL, NULL))) + com_err(program_name, stat, " in UpdateContainer."); + else + Put_message("Container successfully updated."); +} + +int DeleteContainer(int argc, char **argv) +{ + struct mqelem *top; + + top = GetMCInfo(CONTAINER, argv[1], NULL); + QueryLoop(top, PrintClusterInfo, RealDeleteContainer, + "Delete the container"); + + FreeQueue(top); + return DM_NORMAL; +} + +static void RealDeleteContainer(char **info, Bool one_container) +{ + int stat; + char temp_buf[BUFSIZ]; + + sprintf(temp_buf, + "Are you sure you want to delete the container %s (y/n) ?", + info[CON_NAME]); + if (!one_container || Confirm(temp_buf)) + { + if (CheckAndRemoveMachinesFromContainer(info[CON_NAME], TRUE) + != SUB_ERROR) + { + if ((stat = do_mr_query("delete_container", 1, &info[CON_NAME], + NULL, NULL))) + { + com_err(program_name, stat, " in delete_container."); + sprintf(temp_buf, "Container %s ** NOT ** deleted.", + info[CON_NAME]); + Put_message(temp_buf); + } + else + { + sprintf(temp_buf, "Container %s successfully deleted.", + info[CON_NAME]); + Put_message(temp_buf); + } + } + } +} + +int CheckAndRemoveMachinesFromContainer(char *name, Bool ask_first) +{ + int stat, ret_value; + Bool delete_it; + char *args[10], temp_buf[BUFSIZ], *ptr; + struct mqelem *top, *elem = NULL; + + ret_value = SUB_NORMAL; + args[0] = name; + args[1] = "0"; + stat = do_mr_query("get_machines_of_container", 2, args, StoreInfo, + &elem); + if (stat && stat != MR_NO_MATCH) + { + com_err(program_name, stat, " in get_machines_of_container"); + return DM_NORMAL; + } + if (stat == MR_SUCCESS) + { + elem = top = QueueTop(elem); + if (ask_first) + { + sprintf(temp_buf, + "The container %s has the following machines in it:", name); + Put_message(temp_buf); + while (elem) + { + char **info = elem->q_data; + Print(1, &info[0], (char *) NULL); + elem = elem->q_forw; + } + ptr = "Remove ** ALL ** these machines from this container?"; + + if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */ + delete_it = TRUE; + else + { + Put_message("Aborting..."); + FreeQueue(top); + return SUB_ERROR; + } + } + else + delete_it = TRUE; + + if (delete_it) + { + elem = top; + while (elem) + { + char **info = elem->q_data; + if ((stat = do_mr_query("delete_machine_from_container", + 2, info, NULL, NULL))) + { + ret_value = SUB_ERROR; + com_err(program_name, stat, + " in delete_machine_from_container."); + sprintf(temp_buf, + "Machine %s ** NOT ** removed from container %s.", + info[0], info[1]); + Put_message(temp_buf); + } + elem = elem->q_forw; + } + } + } + return ret_value; +} + +int GetSubContainers(int argc, char **argv) +{ + char *args[2]; + struct mqelem *elem = NULL, *top = NULL; + int stat; + + args[0] = argv[1]; + + if (YesNoQuestion("Do you want a recursive search?", TRUE) == TRUE) + args[1] = "1"; + else + args[1] = "0"; + + if (stat = do_mr_query("get_subcontainers_of_container", 2, args, + StoreInfo, &elem)) + com_err(program_name, stat, " in get_subcontainers_of_container"); + + top = QueueTop(elem); + Loop(top, ((void (*)(char **)) PrintContainer)); + FreeQueue(top); + return DM_NORMAL; +} + +int MachineToContainerMap(int argc, char **argv) +{ + struct mqelem *elem, *top; + char *tmpname, temp_buf[256]; + + tmpname = canonicalize_hostname(strdup(argv[1])); + if (strcasecmp(tmpname, argv[1]) && *argv[1] != '"') + { + sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.", + argv[1], tmpname); + Put_message(temp_buf); + } + top = elem = GetMCInfo(CONTMAP, tmpname, NULL); + + Put_message(""); + while (elem) + { + char **info = elem->q_data; + PrintMContMap(info); + elem = elem->q_forw; + } + + FreeQueue(top); + free(tmpname); + return DM_NORMAL; +} + +int AddMachineToContainer(int argc, char **argv) +{ + int stat; + char *machine, *container, temp_buf[BUFSIZ], *args[10]; + Bool add_it, one_machine, one_container; + struct mqelem *melem, *mtop, *celem, *ctop; + + machine = canonicalize_hostname(strdup(argv[1])); + if (strcasecmp(machine, argv[1]) && *argv[1] != '"') + { + sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.", + argv[1], machine); + Put_message(temp_buf); + } + container = argv[2]; + + celem = ctop = GetMCInfo(CONTAINER, container, NULL); + melem = mtop = GetMCInfo(MACHINE, machine, NULL); + free(machine); + + one_machine = (QueueCount(mtop) == 1); + one_container = (QueueCount(ctop) == 1); + + while (melem) + { + char **minfo = melem->q_data; + while (celem) + { + char **cinfo = celem->q_data; + if (one_machine && one_container) + add_it = TRUE; + else + { + sprintf(temp_buf, "Add machine %s to container %s (y/n/q) ?", + minfo[M_NAME], cinfo[CON_NAME]); + switch (YesNoQuestion(temp_buf, FALSE)) + { + case TRUE: + add_it = TRUE; + break; + case FALSE: + add_it = FALSE; + break; + default: + Put_message("Aborting..."); + FreeQueue(ctop); + FreeQueue(mtop); + return DM_NORMAL; + } + } + if (add_it) + { + args[0] = minfo[M_NAME]; + args[1] = cinfo[CON_NAME]; + stat = do_mr_query("add_machine_to_container", 2, args, NULL, + NULL); + switch (stat) + { + case MR_SUCCESS: + break; + case MR_EXISTS: + sprintf(temp_buf, "%s is already in container %s", + minfo[M_NAME], cinfo[CON_NAME]); + Put_message(temp_buf); + break; + default: + com_err(program_name, stat, " in AddMachineToContainer."); + break; + } + } + celem = celem->q_forw; + } + celem = ctop; + melem = melem->q_forw; + } + FreeQueue(ctop); + FreeQueue(mtop); + return DM_NORMAL; +} + +int RemoveMachineFromContainer(int argc, char **argv) +{ + struct mqelem *elem = NULL; + char buf[BUFSIZ], *args[10]; + int stat; + + args[0] = canonicalize_hostname(strdup(argv[1])); + if (strcasecmp(args[0], argv[1]) && *argv[1] != '"') + { + sprintf(buf, "Warning: '%s' canonicalized to '%s'.", + argv[1], args[0]); + Put_message(buf); + } + args[1] = argv[2]; + args[2] = NULL; + + stat = do_mr_query("get_machine_to_container_map", 1, args, StoreInfo, + &elem); + if (stat == MR_NO_MATCH) + { + sprintf(buf, "The machine %s is not in the container %s.", + args[0], args[1]); + Put_message(buf); + free(args[0]); + return DM_NORMAL; + } + if (stat != MR_SUCCESS) + com_err(program_name, stat, " in deleter_machine_from_container"); + + elem = QueueTop(elem); + QueryLoop(elem, PrintMContMap, RealRemoveMachineFromContainer, + "Remove this machine from this container"); + + FreeQueue(elem); + free(args[0]); + return DM_NORMAL; +} + +static void RealRemoveMachineFromContainer(char **info, Bool one_contmap) +{ + char temp_buf[BUFSIZ]; + int stat; + + sprintf(temp_buf, "Remove %s from the container %s", + info[0], info[1]); + if (!one_contmap || Confirm(temp_buf)) + { + if ((stat = do_mr_query("delete_machine_from_container", 2, + info, NULL, NULL))) + com_err(program_name, stat, " in delete_machine_from_container"); + else + { + sprintf(temp_buf, "%s has been removed from the container %s.", + info[0], info[1]); + Put_message(temp_buf); + } + } + else + Put_message("Machine not removed."); +} + +int GetMachinesOfContainer(int argc, char **argv) +{ + char *args[2]; + struct mqelem *elem = NULL, *top = NULL; + int stat; + + args[0] = argv[1]; + + if (YesNoQuestion("Do you want a recursive search?", TRUE) == TRUE) + args[1] = "1"; + else + args[1] = "0"; + + if (stat = do_mr_query("get_machines_of_container", 2, args, + StoreInfo, &elem)) + com_err(program_name, stat, " in get_machines_of_container"); + + top = QueueTop(elem); + Loop(top, ((void (*)(char **)) PrintMContMap)); + FreeQueue(top); + return DM_NORMAL; +}