Advertisement
GarbageYard

Remote build using SSH/rexec

Aug 13th, 2012
218
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.92 KB | None | 0 0
  1. // Requires: ssh and nmap executables
  2. #include <string>
  3. #include <iostream>
  4.  
  5. #include <unistd.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <sys/types.h>
  9. #include <sys/socket.h>
  10. #include <sys/ioctl.h>
  11. #include <sys/wait.h>
  12. #include <signal.h>
  13. #include <netinet/in.h>
  14. #include <netdb.h>
  15. #include <errno.h>
  16. #include <iostream>
  17.  
  18. #define    MAX_HOSTS    32
  19. #define    BUF_TO_READ_SIZE 256 // in bytes
  20.  
  21. using namespace std;
  22.  
  23. int hostCount, pid[MAX_HOSTS];
  24. char **hosts;
  25.  
  26. void killChildren()
  27. {
  28.     for (int i = 0; i < hostCount; i++) {
  29.         if (pid[i] > 0) {
  30.             kill(pid[i], SIGINT);
  31.             cout << "Sent kill signal to pid " << pid[i] << ", host \"" << hosts[i] << "\"\n";
  32.         }
  33.     }
  34. }
  35.  
  36. /* Handle signals */
  37. void handle_SIGINT(int signal)
  38. {
  39.     if (pid[hostCount] != 0) {
  40.         /* This is the parent process.  Send signals to children. */
  41.         killChildren();
  42.     }
  43.     exit(1);
  44. }
  45.  
  46. int isRunningSSH(string hostname)
  47. {
  48.     string nmapCmd = "nmap -sT -oG - -p 22 -n ";
  49.     nmapCmd += hostname;
  50.     nmapCmd += " | grep '22.open.*ssh' > /dev/null 2>&1";
  51.     int ret(system(nmapCmd.c_str()));
  52.     fflush(0);
  53.     return (0 == ret);
  54. }
  55.  
  56. int isRunningRexec(string hostname)
  57. {
  58.     string nmapCmd = "nmap -sT -oG - -p 512 -n ";
  59.     nmapCmd += hostname;
  60.     nmapCmd += " | grep '512.open.*exec' > /dev/null 2>&1";
  61.     int ret(system(nmapCmd.c_str()));
  62.     fflush(0);
  63.     return (0 == ret);
  64. }
  65.  
  66. int runRbuildOnHostUsingSSH(const string hostname, const string username, const string command)
  67. {
  68.     int pid, status, outpipe[2];
  69.     FILE *pipe_file;
  70.     int ret = 0;
  71.     const char *ssh_prog = "/usr/bin/ssh";
  72.  
  73.     cout << "Command: " << command << endl;
  74.     fflush(0);
  75.  
  76.     outpipe[0] = outpipe[1] = 0;
  77.     pipe(outpipe);
  78.  
  79.     if (!(pid = fork())) {
  80.         close(outpipe[0]);
  81.         dup2(outpipe[1], STDERR_FILENO);
  82.  
  83.         char *new_env[] = { NULL };
  84.  
  85.         execle(ssh_prog, ssh_prog,
  86.                 "-x", /* No X tunneling */
  87.                 "-n", /* No input from stdin */
  88.                 "-l",
  89.                 username.c_str(),
  90.                 hostname.c_str(),
  91.                 command.c_str(),
  92.                 NULL,
  93.                 new_env);
  94.         fprintf(stderr, "Unable to run %s\n", ssh_prog);
  95.         exit(1);
  96.     }
  97.  
  98.     close(outpipe[1]);
  99.     pipe_file = fdopen(outpipe[0], "r");
  100.     char buf[1024];
  101.     while (fgets(buf, 1024, pipe_file)) {
  102.         fputs(buf, stdout);
  103.         fflush(stdout);
  104.     }
  105.     fclose(pipe_file);
  106.  
  107.     waitpid(pid, &status, 0);
  108.     if (! WIFEXITED(status)) {
  109.         cout << "SSH subprocess exited abnormally " << endl;
  110.         ret = -1;
  111.     } else {
  112.         cout << "SSH subprocess exit value: " << WEXITSTATUS(status) << endl;
  113.         ret = WEXITSTATUS(status);
  114.     }
  115.  
  116.     return ret;
  117. }
  118.  
  119.  
  120. int runRbuildOnHostUsingRexec(string hostname, int port, string username, string password, string command)
  121. {
  122.     int returnCode, ch, socketDescriptor;
  123.     char *host_ptr;
  124.  
  125.     host_ptr = (char *) hostname.c_str();
  126.     socketDescriptor = rexec(&host_ptr, port, username.c_str(), password.c_str(), command.c_str(), 0);
  127.     if (socketDescriptor != (-1)) {
  128.         cout << "Command: " << command << endl;
  129.         int readCount = 0;
  130.         FILE *fp = fdopen(socketDescriptor, "r");
  131.         fflush(0);
  132.         while ((ch = getc(fp)) != EOF) {
  133.             putchar(ch);
  134.             if (++readCount >= BUF_TO_READ_SIZE) {
  135.                 readCount = 0;
  136.                 fflush(stdout);
  137.             }
  138.         }
  139.         fclose(fp);
  140.         close(socketDescriptor);
  141.         returnCode = 0;
  142.     } else {
  143.  
  144.         cout << "Unable to connect to host " << hostname << " with username " << username << "\n";
  145.         returnCode = -1;
  146.     }
  147.     return returnCode;
  148. }
  149.  
  150. int doRbuildOnHost(string hostname, int port, string username, string password, string command)
  151. {
  152.     time_t startTime, finishTime;
  153.  
  154.     cout << endl << "Host: " << hostname << "\tLogin: " << username << endl;
  155.  
  156.     time(&startTime);
  157.     if (isRunningSSH(hostname)) {
  158.         runRbuildOnHostUsingSSH(hostname, username, command);
  159.     } else if (isRunningRexec(hostname)) {
  160.         runRbuildOnHostUsingRexec(hostname, port, username, password, command);
  161.     } else {
  162.         cout << endl << endl << "Error: The remote host '" << hostname << "' does not support ssh or rexec." << endl << endl;
  163.     }
  164.  
  165.     time(&finishTime);
  166.     int minutes = (finishTime - startTime) / 60;
  167.     int seconds = (finishTime - startTime) % 60;
  168.     cout << endl << "Running Time: " << minutes << " minutes, " << seconds << " seconds" << endl;
  169. }
  170.  
  171. int main(int argc, char **argv)
  172. {
  173.     string username("abc");
  174.     string password("common");
  175.     string buildCommand("");
  176.     string buildCommand_withld("");
  177.     string ldlibcommand("");
  178.     string javapathcommand("");
  179.     string classpathcmd("");
  180.     string java_home("");
  181.     string basePath("");
  182.     string logPathPrefix("");
  183.     struct servent *servent;
  184.     int ch;
  185.     string tmpPath;
  186.     int errorFlag = 0, basePathFlag = 0, executeFlag = 0, logPathPrefixFlag = 0;
  187.     int redirectStdout = 1;
  188.     int buildCommandFlag = 0;
  189.     time_t startTime;
  190.     time_t rexecTimeout = 24 * 60 * 60; // 24 hours, measured in seconds
  191.  
  192.     while ((ch = getopt(argc, argv, "hsb:c:e:t:u:p:l:")) != EOF) {
  193.         switch (ch) {
  194.             case 'b':
  195.                 basePath = string(optarg);
  196.                 basePathFlag++;
  197.                 break;
  198.             case 'l':
  199.                 logPathPrefix = string(optarg);
  200.                 logPathPrefixFlag++;
  201.                 break;
  202.             case 's':
  203.                 redirectStdout = 0;
  204.                 break;
  205.             case 'c': // manually specify build target with some default pre-setup
  206.                 buildCommand = string(optarg);
  207.                 buildCommandFlag++;
  208.                 break;
  209.             case 'e': // manually specify entire rexec command
  210.                 buildCommand = string(optarg);
  211.                 executeFlag = 1;
  212.                 buildCommandFlag++;
  213.                 break;
  214.             case 't': // Specify timeout in minutes
  215.                 rexecTimeout = (time_t) strtol(optarg, NULL, 10);
  216.                 break;
  217.             case 'u': // Specify username
  218.                 username = optarg;
  219.                 break;
  220.             case 'p': // Specify password
  221.                 password = optarg;
  222.                 break;
  223.             case 'h':
  224.             default:
  225.                 errorFlag = 1;
  226.                 break;
  227.         }
  228.     }
  229.     if (optind >= argc) {
  230.         errorFlag = 1;
  231.         cerr << "Error: You must specify host names\n";
  232.     } else {
  233.         hosts = &argv[optind];
  234.     }
  235.  
  236.     /* Initialize pid info */
  237.     for (int i = 0; i < MAX_HOSTS; i++) {
  238.         pid[i] = (-1);
  239.     }
  240.  
  241.     /* Initialize command strings */
  242.     if (! executeFlag) {
  243.         // User used -c
  244.     ldlibcommand = "LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH; export LD_LIBRARY_PATH;";
  245.     java_home="/unixhome/jdk1.6.0_21/unix";
  246.     javapathcommand = "JAVA_HOME=" + java_home + ";export JAVA_HOME;";
  247.  
  248.     classpathcmd = "CLASSPATH=" + java_home + "/jre/lib:" + java_home + "/lib:.;export CLASSPATH;";
  249.        
  250.         buildCommand_withld = "PATH=" + java_home + "/bin:/usr/local/bin:/usr/bin:$PATH; export PATH;" + ldlibcommand + javapathcommand +  classpathcmd + " cd " + basePath + "; echo UNAME: `uname -a`; " + buildCommand + " ; [ 0 -eq $? ] && echo SUCCESSFUL BUILD";
  251.        
  252.         buildCommand = "PATH=/bin:/usr/local/bin:/usr/bin:$PATH; export PATH; cd " + basePath + "; echo UNAME: `uname -a`; " + buildCommand + " ; [ 0 -eq $? ] && echo SUCCESSFUL BUILD";
  253.     }
  254.    
  255.     /* Reopen stdout and stderr to files */
  256.     if (redirectStdout) {
  257.         if (isatty( fileno( stdout )))
  258.             cout << "Redirecting stdout and stderr to rbuild.log and to " << logPathPrefix << "* files.\nUse the -s option if you want to see the output.\n";
  259.         tmpPath = "rbuild.log";
  260.         freopen(tmpPath.c_str(), "w", stdout);
  261.         freopen(tmpPath.c_str(), "w", stderr);
  262.     }
  263.  
  264.     time(&startTime);
  265.  
  266.     /* Handle SIGINT */
  267.     signal(SIGINT, handle_SIGINT);
  268.     signal(SIGTERM, handle_SIGINT);
  269.  
  270.     /* Get service port */
  271.     servent = getservbyname("exec", "tcp");
  272.  
  273.     fflush(0);
  274.  
  275.     /* Spawn children and send command to each host */
  276.     hostCount = 0;
  277.     string host;
  278.     while (hosts[hostCount] && (hostCount < MAX_HOSTS)) {
  279.         host = hosts[hostCount];
  280.         tmpPath = logPathPrefix + host;
  281.         pid[hostCount] = fork();
  282.         if (0 == pid[hostCount]) {
  283.             // Child
  284.             if (redirectStdout) {
  285.                 freopen(tmpPath.c_str(), "w", stdout);
  286.                 freopen(tmpPath.c_str(), "w", stderr);
  287.             }
  288.             if(!host.compare("SOLSPARC"))
  289.             buildCommand = buildCommand_withld ;
  290.             doRbuildOnHost(host, servent->s_port, username, password, buildCommand);
  291.             exit(0); // The child process should exit at this point
  292.         } else if (-1 == pid[hostCount]) {
  293.             cout << "Couldn't fork for host \"" << host << "\"\n";
  294.         } else {
  295.             cout << "Remote execute started for host \"" << host << "\", logfile: \"" << tmpPath << "\", pid: " << pid[hostCount] << " \n";
  296.         }
  297.         hostCount++;
  298.     }
  299.  
  300.     /* Wait for all sub-processes to exit */
  301.     int statval;
  302.     time_t runningTime;
  303.     int child_pid;
  304.     do {
  305.         child_pid = waitpid(0, &statval, WNOHANG);
  306.         if (child_pid == -1 && errno == ECHILD) {
  307.             break; // All children have exited
  308.         }
  309.         if (rexecTimeout) {
  310.             time(&runningTime);
  311.             if ( (runningTime - startTime) > rexecTimeout )  {
  312.                 cout << "Reached timeout of " << rexecTimeout << " seconds; killing rexec processes.\n";
  313.                 killChildren();
  314.                 rexecTimeout = 0; // We should never come back here again
  315.             }
  316.         }
  317.         sleep(1);
  318.     } while (1);
  319.  
  320.     fflush(0);
  321.     return 0;
  322. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement