addServer(); $worker->addFunction("invoke_image_build", "image_build"); $worker->addFunction("invoke_start_image", "start_image"); while ($worker->work()) { // Do nothing! }; function update_result($handle, $returncode, $result) { $result = trim($result); echo "A job finished with return code ".$returncode.": ".$result."\n"; $db = new mysqli( MYSQL_HOSTNAME, MYSQL_USERNAME, MYSQL_PASSWORD, MYSQL_DATABASE ); if (mysqli_connect_errno()) { die("Could not connect to database ".mysqli_connect_error()); } $query = "UPDATE builds SET result = ?, returncode = ? ". "WHERE handle = ?"; $stmt = $db->prepare($query); $stmt->bind_param("sds", $result, $returncode, $handle); $stmt->execute(); $stmt->close(); $query = "SELECT id, email FROM builds WHERE handle = ?"; $stmt = $db->prepare($query); $stmt->bind_param("s", $handle); $stmt->execute(); $stmt->bind_result($buildID, $email); $stmt->fetch(); if($email != null) { $headers = array('From' => SMTP_EMAIL, 'To' => $email, 'Subject' => "Your Gentoaster build has completed"); $smtp = Mail::factory('smtp', array ('host' => SMTP_HOST, 'auth' => true, 'username' => SMTP_USERNAME, 'password' => SMTP_PASSWORD)); $body = "Your Gentoaster build has finished.\n\n" ."You can view the results at ".GENTOASTER_URL ."/status.php?uuid=".$buildID; $mail = $smtp->send($email, $headers, $body); } $stmt->close(); $db->close(); return serialize(array($returncode, $result)); } function check_pid($pid) { $cmd = "ps $pid"; exec($cmd, $output, $result); if (count($output) >= 2) { return true; } return false; } function image_build($job) { $progressMagic = 24; $handle = $job->handle(); $handlehash = md5($handle); echo "Processing job handle hash ".$handlehash."\n"; $configurationString = $job->workload(); $configurationArray = parse_ini_string($configurationString); if ($configurationArray !== false) { if (isset($configurationArray["BUILD_ID"])) { $buildID = $configurationArray["BUILD_ID"]; $buildPath = CONFIGURATIONS_PATH."/".$buildID; @mkdir($buildPath, 0777, true); if (is_writable($buildPath)) { chdir($buildPath); file_put_contents("config.ini", $configurationString); $toolArgs = "--config config.ini --compress"; $cmd = GENTOASTER_PATH."/".BUILD_TOOL_NAME." ".$toolArgs; $processHandle = popen($cmd." 2>&1", "r"); $nonstatusOutput = ""; while (!feof($processHandle)) { $progressLine = fgets($processHandle); preg_match("/Step (.+):/", $progressLine, $matches); if (sizeof($matches) > 0) { $job->sendStatus($matches[1], $progressMagic); } elseif (substr($progressLine, 0, 5) == "yes: ") { // do nothing } else { $nonstatusOutput .= $progressLine; } } $returncode = pclose($processHandle); unlink("config.ini"); return update_result( $handle, $returncode, $nonstatusOutput ); } else { $error = "Configured build path is not writable"; return update_result($handle, -2, $error); } } else { $error = "Configuration file is incomplete"; return update_result($handle, -3, $error); } } else { $error = "Configuration string is not valid"; return update_result($handle, -4, $error); } } function start_image($job) { $buildID = $job->workload(); $running = false; $insert = false; $update = false; $db = new mysqli( MYSQL_HOSTNAME, MYSQL_USERNAME, MYSQL_PASSWORD, MYSQL_DATABASE ); if (mysqli_connect_errno()) { die("Could not connect to database ".mysqli_connect_error()); } $query = "UPDATE builds SET result = ?, returncode = ? ". "WHERE handle = ?"; $stmt = $db->prepare($query); $stmt->bind_param("sds", $result, $returncode, $handle); $stmt->execute(); $stmt->close(); $query = "SELECT port FROM ports ORDER BY port DESC LIMIT 1"; $stmt = $db->prepare($query); $stmt->execute(); if ($stmt->num_rows == 0) { // no ports! assign a new one $stmt->close(); $port = LOW_PORT; $insert = true; echo "No ports! Assigning ".$port."\n"; } else { // we have a port! let's check if our vm has one $stmt->bind_result($lastport); $stmt->fetch(); $stmt->close(); $query = "SELECT port, pid FROM ports WHERE id = ?"; $stmt = $db->prepare($query); $stmt->bind_param("s", $buildID); $stmt->execute(); if ($stmt->num_rows == 0) { // vm doesn't have one, assign one! $stmt->close(); $port = $lastport+1; if ($port > HIGH_PORT) { $port = LOW_PORT; } $insert = true; echo "Assigning new port ".$port."\n"; } else { // vm already has one, return it $stmt->bind_result($port, $pid); $stmt->fetch(); $stmt->close(); $running = true; if (!check_pid($pid)) { $running = false; $update = true; echo "VM is not running, PID ".$pid." is dead!\n"; } else { echo "VM is running on PID ".$pid."\n"; } echo "VM already has port ".$port."\n"; } } if (!$running || $update) { $cmd = GENTOASTER_PATH."/".WRAP_TOOL_NAME." ". CONFIGURATIONS_PATH."/".$buildID."/".$buildID.".image ". $port." ".TESTDRIVE_MEMORY."&"; $handle = proc_open($cmd, array(), $foo); $status = proc_get_status($handle); $pid = $status["pid"]; echo "New process spawned with PID ".$pid."\n"; proc_close($handle); } // qemu pid is two up // hacky? works for now though $pid = $pid + 2; if ($insert) { $query = "DELETE FROM ports WHERE port = ?"; $stmt = $db->prepare($query); $stmt->bind_param("d", $port); $stmt->execute(); $stmt->close(); $query = "INSERT INTO ports (id, port, pid) VALUES(?, ?, ?)"; $stmt = $db->prepare($query); $stmt->bind_param("sdd", $buildID, $port, $pid); $stmt->execute(); $stmt->close(); echo "Doing insert!\n"; } elseif ($update) { $query = "UPDATE ports SET pid = ? WHERE id = ?"; $stmt = $db->prepare($query); $stmt->bind_param("ds", $pid, $buildID); $stmt->execute(); $stmt->close(); echo "Doing update\n"; } $db->close(); $port = $port+1000; return serialize(array(EXTERNAL_HOST, $port)); }