/usr/sbin/cabal

     1	#!/bin/bash
     2	#---------------------------------------------------------------------
     3	## @Synopsis A set of functions for the Cabal distributed administration system.
     4	## @Copyright Copyright 2002 by the Source Mage Team. Some parts Copyright 2001 by Kyle Sallee
     5	## Control a set of SourceMage boxes on a network. This documentation was
     6	## written by someone who never used cabal or looked at this code before.
     7	##
     8	## @Globals CABAL_DIRECTORY CABAL_NAMES MAX_CABALS
     9	#---------------------------------------------------------------------
    10	
    11	#------------------
    12	## Get the names of the machines in the cabal and store in CABAL
    13	## @Stdout The names of the machines in the cabal
    14	## @Globals CABAL_NAMES CABAL
    15	#------------------
    16	function read_cabal_names()  {
    17	
    18	  mkdir  -p  $CABAL_DIRECTORY
    19	
    20	 [  -f  $CABAL_NAMES  ] || return
    21	
    22	
    23	  eval `awk '{ print "CABALS[" NR-1 "]=\"" $0 "\""; }' "$CABAL_NAMES"`
    24	
    25	}
    26	
    27	#--------------------
    28	## Overwrite the cabal name file with new member names
    29	## @Globals CABAL_NAMES MAX_CABALS
    30	#--------------------
    31	function write_cabal_names()  {
    32	
    33	  rm  -f  $CABAL_NAMES
    34	  for  ((  COUNT=0;  COUNT != ${#CABALS[@]};  COUNT++  ));   do
    35	    echo  "${CABALS[$COUNT]}"  >>  $CABAL_NAMES
    36	  done
    37	
    38	}
    39	
    40	#---------------------
    41	## Print out the member of the cabal (assuming the names have been read)
    42	## @Globals MAX_CABALS
    43	## @Stdout Names of each cabal member
    44	## @NOTE MAX_CABAL can be eliminated
    45	#---------------------
    46	function print_cabal_names()  {
    47	
    48	eval ${DIALOG}  '--textbox  ${CABAL_NAMES}  0  0'
    49	
    50	#for  ((  COUNT = 0;  COUNT  !=  MAX_CABALS;  COUNT++  ));  do
    51	#    echo  "${CABALS[$COUNT]}"
    52	#done
    53	
    54	}
    55	
    56	#---------------------
    57	## Outputs the number and name of each cabal member
    58	## @Stdout <number>\n<cabal name or "Undefined"> for all cabal members
    59	## @NOTE Dito about MAX_CABALS
    60	#---------------------
    61	function print_cabal_numbers_names()  {
    62	
    63	  for  ((  COUNT = 0;  COUNT  !=  MAX_CABALS;  COUNT++  ));  do
    64	    echo  "$COUNT"
    65	    if    [  -n  "${CABALS[$COUNT]}"  ]
    66	    then  echo   "${CABALS[$COUNT]}"
    67	    else  echo   "Undefined"
    68	    fi
    69	  done
    70	
    71	}
    72	
    73	#-----------------------
    74	## Pops up a dialog box for selecting a specific cabal member
    75	## @Stdout dialog output
    76	## @Stderr Cabal member selection
    77	#-----------------------
    78	function select_cabal()  {
    79	
    80	  eval $DIALOG  '--title         "Cabal Selection Menu"  \
    81	           --ok-label      "Select"                \
    82	           --cancel-label  "Exit"                  \
    83	           --menu                                  \
    84	           "Please Select a Cabal"                 \
    85	           0 0 0                                   \
    86	           $( print_cabal_numbers_names )'
    87	
    88	}
    89	
    90	#----------------------
    91	## Edit the file about selected members
    92	#----------------------
    93	function edit_cabals()  {
    94	
    95	  while  SELECTED=`select_cabal`
    96	  do     edit_file  "$CABAL_DIRECTORY/$SELECTED"
    97	  done
    98	
    99	}
   100	
   101	#---------------------
   102	## Show contents of a member's info file
   103	#---------------------
   104	function show_cabals()  {
   105	
   106	  while  SELECTED=`select_cabal`
   107	  do     show_file  "$CABAL_DIRECTORY/$SELECTED"
   108	  done
   109	
   110	}
   111	
   112	#--------------------
   113	## Generate SSH key for a cabal member
   114	#--------------------
   115	function generate_cabal_key()  {
   116	
   117	  while  SELECTED=`select_cabal`
   118	  do
   119	
   120	    mkdir  -p   $CABAL_KEYS
   121	    chmod  600  $CABAL_KEYS
   122	
   123	    ssh-keygen  -t  dsa  \
   124	                -b  1024 \
   125	                -N  ""   \
   126	                -f  $CABAL_KEYS/$SELECTED
   127	
   128	  done
   129	
   130	}
   131	
   132	
   133	function all_cabal_keys()  {
   134	
   135	  for  KEY  in  `ls  $CABAL_KEYS/*  |
   136	                 grep  -v  "\.pub"`
   137	  do  echo  "-i"
   138	      echo  "$KEY"
   139	  done
   140	
   141	}
   142	
   143	
   144	function distribute_cabal_key()  {
   145	
   146	  while  SELECTED=`select_cabal`
   147	  do
   148	
   149	    mkdir  -p   $CABAL_KEYS
   150	    chmod  600  $CABAL_KEYS
   151	
   152	    if  !  [  -e  $CABAL_KEYS/$SELECTED.pub  ];  then
   153	      eval $DIALOG  --msgbox  "Generate the key first!"
   154	      return
   155	    fi
   156	
   157	    AK2="/root/.ssh/authorized_keys2"
   158	    # TODO check that the following works, since it is reading and writing to
   159	    # the same file - $AK2
   160	    cat    $CABAL_DIRECTORY/$SELECTED  |
   161	    while  read  BOX
   162	    do     cat  $CABAL_KEYS/$SELECTED.pub  |
   163	           ssh  `all_cabal_keys`           \
   164	                root@$BOX                  \
   165	                "cat   >>  $AK2;           \
   166	                 sort      $AK2  |         \
   167	                 uniq  >   $AK2"
   168	    done
   169	  done
   170	
   171	}
   172	
   173	
   174	function revoke_cabal_key()  {
   175	
   176	  while  SELECTED=`select_cabal`
   177	  do
   178	
   179	    mkdir  -p   $CABAL_KEYS
   180	    chmod  600  $CABAL_KEYS
   181	
   182	    if  !  [  -e  $CABAL_KEYS/$SELECTED.pub  ];  then
   183	      eval $DIALOG  --msgbox  "No key to revoke!"
   184	      return
   185	    fi
   186	
   187	    AK2="/root/.ssh/authorized_keys2"
   188	
   189	    cat    $CABAL_DIRECTORY/$SELECTED  |
   190	    while  read  BOX
   191	    do     REVOKE=KEY="`cat  $CABAL_KEYS/$SELECTED.pub`"
   192	           ssh  `all_cabal_keys`                   \
   193	                root@$BOX                          \
   194	                "grep  -v  "$REVOKE_KEY"  $AK2  |  \
   195	                 sort                  >  $AK2"
   196	    done
   197	  done
   198	
   199	}
   200	
   201	
   202	name_cabals()  {
   203	
   204	   TITLE="Name Cabals Menu"
   205	    HELP="Please enter cabal's name"
   206	
   207	  while  SELECTED=`select_cabal`
   208	  do
   209	
   210	    if  NAME=`$DIALOG  --title         "$TITLE"  \
   211	                       --ok-label      "Enter"   \
   212	                       --cancel-label  "Cancel"  \
   213	                       --inputbox                \
   214	                       "$HELP"                   \
   215	                       0 0 ${CABALS[$SELECTED]}`
   216	    then
   217	      CABALS[$SELECTED]="$NAME"
   218	    fi
   219	  done
   220	
   221	  write_cabal_names
   222	
   223	}
   224	
   225	
   226	function set_max_cabals()  {
   227	
   228	  PROMPT="Please enter the maximum number of cabals"
   229	
   230	  if  NEW_MAX=`eval $DIALOG  '--ok-label  "Commit"  \
   231	                        --inputbox            \
   232	                        "$PROMPT"             \
   233	                        0 0  "$MAX_CABALS"'`
   234	  then
   235	    MAX_CABALS=$NEW_MAX
   236	    modify_local_config "MAX_CABALS" $MAX_CABALS
   237	  fi
   238	
   239	}
   240	
   241	
   242	function cabal_name_menu()  {
   243	
   244	  while
   245	
   246	      HELP=""
   247	    S_HELP="Show the names of the cabals"
   248	    E_HELP="Edit the names of the cabals"
   249	     TITLE="Cabal Name Menu"
   250	
   251	    COMMAND=`eval $DIALOG '--title         "$TITLE"            \
   252	                     --item-help                         \
   253	                     --ok-label      "Select"            \
   254	                     --cancel-label  "Exit"              \
   255	                     --menu                              \
   256	                     "$HELP"                             \
   257	                     0 0 0                               \
   258	                     "S"  "Show Cabal Names"  "$S_HELP"  \
   259	                     "E"  "Edit Cabal Names"  "$E_HELP"'`
   260	  do
   261	
   262	    case  $COMMAND in
   263	      S)  print_cabal_names   ;;
   264	      E)  name_cabals                   ;;
   265	    esac
   266	
   267	  done
   268	
   269	}
   270	
   271	
   272	function cabal_key_menu()  {
   273	
   274	  while
   275	
   276	      HELP="Generate, distribute, and revoke ssh2 keys to cabal computers to
   277	enable root login without password prompts"
   278	    G_HELP="Create 2048 bit ssh2 dsa public/private keys for a cabal."
   279	    D_HELP="Install the public key on all computer members of cabal."
   280	    R_HELP="Remove a previously installed cabal key"
   281	     TITLE="Cabal Key Menu"
   282	
   283	    COMMAND=`eval $DIALOG '--title         "$TITLE"                 \
   284	                     --item-help                              \
   285	                     --ok-label      "Select"                 \
   286	                     --cancel-label  "Exit"                   \
   287	                     --menu                                   \
   288	                     "$HELP"                                  \
   289	                     0 0 0                                    \
   290	                     "G"  "Generate    Cabal Key"  "$G_HELP"  \
   291	                     "D"  "Distribute  Cabal Key"  "$D_HELP"  \
   292	                     "R"  "Revoke      Cabal Key"  "$R_HELP"'`
   293	  do
   294	
   295	    case  $COMMAND in
   296	      G)  generate_cabal_key    ;;
   297	      D)  distribute_cabal_key  ;;
   298	      R)  revoke_cabal_key      ;;
   299	    esac
   300	
   301	  done
   302	
   303	}
   304	
   305	
   306	function cabal_content_menu()  {
   307	
   308	  while
   309	
   310	      HELP=""
   311	    S_HELP="Show the computers which belong to a cabal"
   312	    E_HELP="Edit the computers which belong to a cabal"
   313	     TITLE="Cabal Content Menu"
   314	
   315	    COMMAND=`eval $DIALOG '--title         "$TITLE"       \
   316	                     --item-help                    \
   317	                     --ok-label      "Select"       \
   318	                     --cancel-label  "Exit"         \
   319	                     --menu                         \
   320	                     "$HELP"                        \
   321	                     0 0 0                          \
   322	                     "S"  "Show  Cabal"  "$S_HELP"  \
   323	                     "E"  "Edit  Cabal"  "$E_HELP"'`
   324	  do
   325	
   326	    case  $COMMAND in
   327	      S)  show_cabals  ;;
   328	      E)  edit_cabals  ;;
   329	    esac
   330	
   331	  done
   332	
   333	}
   334	
   335	
   336	function select_order()  {
   337	
   338	  eval $DIALOG  '--title  "Order Selection Menu"  \
   339	           --menu  ""  0 0 0                \
   340	           "S"  "Sequentially"              \
   341	           "C"  "Concurrently"'
   342	
   343	}
   344	
   345	
   346	function cabal_admin_menu()  {
   347	
   348	  while
   349	
   350	      HELP=""
   351	    M_HELP="Define maximum amount of cabals."
   352	    N_HELP="Define and display the names of cabals"
   353	    C_HELP="Define and display the computers belong to a cabal"
   354	    K_HELP="Generate and distribute keys for cabals"
   355	     TITLE="Cabal Admin Menu"
   356	
   357	    COMMAND=`eval $DIALOG '--title         "$TITLE"                 \
   358	                     --item-help                              \
   359	                     --ok-label      "Select"                 \
   360	                     --cancel-label  "Exit"                   \
   361	                     --menu                                   \
   362	                     "$HELP"                                  \
   363	                     0 0 0                                    \
   364	                     "N"  "Cabal Name       Menu"  "$N_HELP"  \
   365	                     "C"  "Cabal Content    Menu"  "$C_HELP"  \
   366	                     "K"  "Cabal Key        Menu"  "$K_HELP"  \
   367	                     "M"  "Maximum Cabals:  $MAX_CABALS"   "$M_HELP"'`
   368	
   369	  do
   370	
   371	    case  $COMMAND in
   372	      N)  cabal_name_menu     ;;
   373	      C)  cabal_content_menu  ;;
   374	      K)  cabal_key_menu      ;;
   375	      M)  set_max_cabals      ;;
   376	    esac
   377	
   378	  done
   379	
   380	}
   381	
   382	
   383	function cabal_copy()  {
   384	
   385	  SOURCE_MESSAGE='"Please enter source files and directories."'
   386	    DEST_MESSAGE='"Please enter destination directory."'
   387	
   388	  mkdir  -p  $CABAL_OUTPUT || {
   389	    messasge "Failed to make CABAL_OUTPUT directory $CABAL_OUTPUT"
   390	    exit 1
   391	  }
   392	
   393	       SOURCE=`eval $DIALOG  --inputbox  $SOURCE_MESSAGE  0 0`  &&
   394	  DESTINATION=`eval $DIALOG  --inputbox  $DEST_MESSAGE    0 0`  &&
   395	        CABAL=`select_cabal`                                 &&
   396	        ORDER=`select_order`                                 &&
   397	
   398	  case  $ORDER  in
   399	    C)  cat  $CABAL_DIRECTORY/$CABAL  |
   400	        while  read  BOX;  do
   401	          scp  -i  $CABAL_KEYS/$CABAL    \
   402	               -r  $SOURCE               \
   403	               root@${BOX}:$DESTINATION  \
   404	          >  $CABAL_OUTPUT/$BOX          &
   405	        done
   406	        ;;
   407	    S)  cat  $CABAL_DIRECTORY/$CABAL  |
   408	        while  read  BOX;  do
   409	          scp  -i  $CABAL_KEYS/$CABAL    \
   410	               -r  $SOURCE               \
   411	               root@${BOX}:$DESTINATION
   412	        done
   413	        read  -n 1  -p  "Press any key to continue"
   414	        ;;
   415	  esac
   416	
   417	}
   418	
   419	
   420	function cabal_execute()  {
   421	
   422	  COMMAND_MESSAGE="Please enter command to be execute remotely on cabal."
   423	
   424	  mkdir  -p  $CABAL_OUTPUT || {
   425	    messasge "Failed to make CABAL_OUTPUT directory $CABAL_OUTPUT"
   426	    exit 1
   427	  }
   428	
   429	  COMMAND=`eval $DIALOG  '--inputbox  "$COMMAND_MESSAGE"  0 0'`  &&
   430	    CABAL=`select_cabal`                                  &&
   431	    ORDER=`select_order`                                  &&
   432	
   433	  case  $ORDER  in
   434	    C)  cat  $CABAL_DIRECTORY/$CABAL  |
   435	        while  read  BOX;  do
   436	          echo "execing box $BOX" && ssh  -n -i  $CABAL_KEYS/$CABAL  \
   437	                   root@${BOX}         \
   438	                   "$COMMAND"          \
   439	          >  $CABAL_OUTPUT/$BOX        &
   440	        done
   441	        ;;
   442	
   443	    S)  cat $CABAL_DIRECTORY/$CABAL  |
   444	        while  read  BOX;  do
   445	          echo "execing box $BOX" && ssh -n -i  $CABAL_KEYS/$CABAL  \
   446	                   root@${BOX}         \
   447	                   "$COMMAND"
   448	        done
   449	        read  -n 1  -p  "Press any key to continue"
   450	        ;;
   451	  esac
   452	
   453	  #sleep  10   <--not sure why that's there.. --dave
   454	
   455	}
   456	
   457	
   458	function cabal_output()  {
   459	
   460	  if  [  -d  $CABAL_OUTPUT  ];  then
   461	    for  FILE  in  `ls  $CABAL_OUTPUT`;  do
   462	      echo  "*------- $FILE  Beginning Output -------*"
   463	      cat   $CABAL_OUTPUT/$FILE
   464	      echo  "*------- $FILE  Ending Output -------*"
   465	      echo
   466	    done
   467	  fi
   468	}
   469	
   470	
   471	function cabal_enchantment_menu()  {
   472	
   473	  while
   474	
   475	      HELP=""
   476	    C_HELP="Copy files and directories to cabals via scp"
   477	    E_HELP="Execute commands on cabals"
   478	    S_HELP="Show the output of previously execute concurrent commands and
   479	copies"
   480	     TITLE="Enchantment Menu"
   481	
   482	    COMMAND=`eval $DIALOG '--title         "$TITLE"   \
   483	                     --item-help                \
   484	                     --ok-label      "Select"   \
   485	                     --cancel-label  "Exit"     \
   486	                     --menu                     \
   487	                     "$HELP"                    \
   488	                     0 0 0                      \
   489	                     "C"  "Copy"     "$A_HELP"  \
   490	                     "E"  "Execute"  "$E_HELP"  \
   491	                     "S"  "Show"     "$S_HELP"'`
   492	
   493	  do
   494	
   495	    case  $COMMAND in
   496	      C)  cabal_copy               ;;
   497	      E)  cabal_execute            ;;
   498	      S)  cabal_output | ${PAGER}  ;;
   499	    esac
   500	
   501	  done
   502	
   503	}
   504	
   505	
   506	function cabal_menu()  {
   507	
   508	  while
   509	
   510	    read_cabal_names
   511	
   512	      HELP="Administrate Multiple Boxes Simultaneously With Cabal"
   513	    A_HELP="Set up Cabals"
   514	    E_HELP="Execute scripts and copy files."
   515	     TITLE="Cabal Menu"
   516	
   517	    COMMAND=`eval $DIALOG '--title         "$TITLE"          \
   518	                     --item-help                       \
   519	                     --ok-label      "Select"          \
   520	                     --cancel-label  "Exit"            \
   521	                     --menu                            \
   522	                     "$HELP"                           \
   523	                     0 0 0                             \
   524	                     "A"  "Administration"  "$A_HELP"  \
   525	                     "E"  "Enchantment"     "$E_HELP"'`
   526	
   527	  do
   528	
   529	    case  $COMMAND in
   530	      A)  cabal_admin_menu        ;;
   531	      E)  cabal_enchantment_menu  ;;
   532	    esac
   533	
   534	  done
   535	
   536	}
   537	
   538	. /etc/sorcery/config
   539	
   540	if [ -n "${PAGER}" ]
   541	then
   542	  PAGER=`which less`
   543	fi
   544	
   545	DIALOG="${DIALOGPROG} --stdout"
   546	
   547	cabal_menu
   548	
   549	##---------------------------------------------------------------------
   550	##=back
   551	##
   552	##=head1 LICENSE
   553	##
   554	## This software is free software; you can redistribute it and/or modify
   555	## it under the terms of the GNU General Public License as published by
   556	## the Free Software Foundation; either version 2 of the License, or
   557	## (at your option) any later version.
   558	##
   559	## This software is distributed in the hope that it will be useful,
   560	## but WITHOUT ANY WARRANTY; without even the implied warranty of
   561	## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   562	## GNU General Public License for more details.
   563	##
   564	## You should have received a copy of the GNU General Public License
   565	## along with this software; if not, write to the Free Software
   566	## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   567	##
   568	##---------------------------------------------------------------------