/** * Runs a client level pre or post script. * * @param string $type Either "pre" or "post". * * @param int $status Status of previos command. * * @param Client $client Client entity * * @param Job $job Job entity. Null if running at the client level. * * @param Script $script Script entity * * @param string $stats Stats for script environment vars (not stored in DB) * * @return boolean true on success, false on error. * */ protected function runScript($type, $status, $client, $job, $script, $stats) { if ($script === null) { return true; } if (null == $job) { $entity = $client; $context = array('link' => $this->generateClientRoute($client->getId())); $errScriptError = 'Client "%entityid%" %scripttype% script "%scriptname%" execution failed. Diagnostic information follows: %output%'; $errScriptMissing = 'Client "%entityid%" %scripttype% script "%scriptname%" present but file "%scriptfile%" missing.'; $errScriptOk = 'Client "%entityid%" %scripttype% script "%scriptname%" execution succeeded. Output follows: %output%'; $level = 'CLIENT'; // Empty vars (only available under JOB level) $job_name = ''; $owner_email = ''; $recipient_list = ''; $job_total_size = 0; $job_run_size = 0; $job_starttime = 0; $job_endtime = 0; if ($type == 'post') { $client_endtime = $stats['ELKARBACKUP_CLIENT_ENDTIME']; $client_starttime = $stats['ELKARBACKUP_CLIENT_STARTTIME']; } else { $client_endtime = 0; $client_starttime = 0; } } else { $entity = $job; $context = array('link' => $this->generateJobRoute($job->getId(), $client->getId())); $errScriptError = 'Job "%entityid%" %scripttype% script "%scriptname%" execution failed. Diagnostic information follows: %output%'; $errScriptMissing = 'Job "%entityid%" %scripttype% script "%scriptname%" present but file "%scriptfile%" missing.'; $errScriptOk = 'Job "%entityid%" %scripttype% script "%scriptname%" execution succeeded. Output follows: %output%'; $level = 'JOB'; $job_name = $job->getName(); $owner_email = $job->getClient()->getOwner()->getEmail(); $recipient_list = $job->getNotificationsEmail(); $job_total_size = $job->getDiskUsage(); $client_starttime = 0; $client_endtime = 0; if ($type == 'post') { $job_run_size = $stats['ELKARBACKUP_JOB_RUN_SIZE']; $job_starttime = $stats['ELKARBACKUP_JOB_STARTTIME']; $job_endtime = $stats['ELKARBACKUP_JOB_ENDTIME']; } else { $job_run_size = 0; $job_starttime = 0; $job_endtime = 0; } } $scriptName = $script->getName(); $scriptFile = $script->getScriptPath(); if (!file_exists($scriptFile)) { $this->err($errScriptMissing, array('%entityid%' => $entity->getId(), '%scriptfile%' => $scriptFile, '%scriptname%' => $scriptName, '%scripttype%' => $type), $context); return false; } $commandOutput = array(); $command = sprintf('env ELKARBACKUP_LEVEL="%s" ELKARBACKUP_EVENT="%s" ELKARBACKUP_URL="%s" ELKARBACKUP_ID="%s" ELKARBACKUP_PATH="%s" ELKARBACKUP_STATUS="%s" ELKARBACKUP_CLIENT_NAME="%s" ELKARBACKUP_JOB_NAME="%s" ELKARBACKUP_OWNER_EMAIL="%s" ELKARBACKUP_RECIPIENT_LIST="%s" ELKARBACKUP_CLIENT_TOTAL_SIZE="%s" ELKARBACKUP_JOB_TOTAL_SIZE="%s" ELKARBACKUP_JOB_RUN_SIZE="%s" ELKARBACKUP_CLIENT_STARTTIME="%s" ELKARBACKUP_CLIENT_ENDTIME="%s" ELKARBACKUP_JOB_STARTTIME="%s" ELKARBACKUP_JOB_ENDTIME="%s" sudo "%s" 2>&1', $level, 'pre' == $type ? 'PRE' : 'POST', $entity->getUrl(), $entity->getId(), $entity->getSnapshotRoot(), $status, $client->getName(), $job_name, $owner_email, $recipient_list, $client->getDiskUsage(), $job_total_size, $job_run_size, $client_starttime, $client_endtime, $job_starttime, $job_endtime, $scriptFile); exec($command, $commandOutput, $status); if (0 != $status) { $this->err($errScriptError, array('%entityid%' => $entity->getId(), '%output%' => "\n" . implode("\n", $commandOutput), '%scriptname%' => $scriptName, '%scripttype%' => $type), $context); return false; } $this->info($errScriptOk, array('%entityid%' => $entity->getId(), '%output%' => "\n" . implode("\n", $commandOutput), '%scriptname%' => $scriptName, '%scripttype%' => $type), $context); return true; }
protected function runJob(Job $job, $runnableRetains) { $stats[] = array(); $warnings = False; $container = $this->getContainer(); $backupDir = $container->getParameter('backup_dir'); $rsnapshot = $container->getParameter('rsnapshot'); $tmpDir = $container->getParameter('tmp_dir'); $engine = $container->get('templating'); $idClient = $job->getClient()->getId(); $idJob = $job->getId(); $url = $job->getUrl(); $retains = $job->getPolicy()->getRetains(); $includes = array(); $include = $job->getInclude(); if ($include) { $includes = explode("\n", $include); foreach ($includes as &$theInclude) { $theInclude = str_replace('\\ ', '?', trim($theInclude)); } } $excludes = array(); $exclude = $job->getExclude(); if ($exclude) { $excludes = explode("\n", $exclude); foreach ($excludes as &$theExclude) { $theExclude = str_replace('\\ ', '?', trim($theExclude)); } } $syncFirst = (int) $job->getPolicy()->getSyncFirst(); $context = array('link' => $this->generateJobRoute($idJob, $idClient)); $content = $engine->render('BinovoElkarBackupBundle:Default:rsnapshotconfig.txt.twig', array('cmdPreExec' => '', 'cmdPostExec' => '', 'excludes' => $excludes, 'idClient' => sprintf('%04d', $idClient), 'idJob' => sprintf('%04d', $idJob), 'includes' => $includes, 'backupDir' => $backupDir, 'retains' => $retains, 'tmp' => $tmpDir, 'snapshotRoot' => $job->getSnapshotRoot(), 'syncFirst' => $syncFirst, 'url' => $url, 'useLocalPermissions' => $job->getUseLocalPermissions(), 'sshArgs' => $job->getSshArgs())); $confFileName = sprintf("%s/rsnapshot.%s_%s.cfg", $tmpDir, $idClient, $idJob); $fd = fopen($confFileName, 'w'); if (false === $fd) { $this->err('Error opening config file %filename%. Aborting backup.', array('%filename%' => $confFileName), $context); return false; } $bytesWriten = fwrite($fd, $content); if (false === $bytesWriten) { $this->err('Error writing to config file %filename%. Aborting backup.', array('%filename%' => $confFileName), $context); return false; } $ok = fclose($fd); if (false === $ok) { $this->warn('Error closing config file %filename%.', array('%filename%' => $confFileName), $context); } if (!is_dir($job->getSnapshotRoot())) { $ok = mkdir($job->getSnapshotRoot(), 0777, true); if (false === $ok) { $this->err('Error creating snapshot root %filename%. Aborting backup.', array('%filename%' => $job->getSnapshotRoot()), $context); return false; } } foreach ($runnableRetains as $retain) { $status = 0; // pre script execution if needed $mustRunScripts = !$job->getPolicy()->isRotation($retain); if ($mustRunScripts) { foreach ($job->getPreScripts() as $script) { if ($this->runScript('pre', 0, $job->getClient(), $job, $script, $stats)) { $this->info('Job "%jobid%" pre script ok.', array('%jobid%' => $job->getId()), $context); } else { $this->err('Job "%jobid%" pre script error.', array('%jobid%' => $job->getId()), $context); $warnings = True; } } } $job_starttime = time(); // run rsnapshot. sync first if needed $commands = array(); if ($job->getPolicy()->mustSync($retain)) { $commands[] = sprintf('"%s" -c "%s" sync 2>&1', $rsnapshot, $confFileName); } $commands[] = sprintf('"%s" -c "%s" %s 2>&1', $rsnapshot, $confFileName, $retain); foreach ($commands as $command) { $commandOutput = array(); $status = 0; $this->info('Running %command%', array('%command%' => $command), $context); exec($command, $commandOutput, $status); if (0 != $status) { $this->err('Command %command% failed. Diagnostic information follows: %output%', array('%command%' => $command, '%output%' => "\n" . implode("\n", $commandOutput)), $context); $ok = false; break; } else { $this->info('Command %command% succeeded with output: %output%', array('%command%' => $command, '%output%' => implode("\n", $commandOutput)), $context); } } $job_endtime = time(); // get disk usage $du_before = $job->getDiskUsage(); $this->info('Client "%clientid%", Job "%jobid%" du begin.', array('%clientid%' => $job->getClient()->getId(), '%jobid%' => $job->getId()), $context); $du = (int) shell_exec(sprintf("du -ks '%s' | sed 's/\t.*//'", $job->getSnapshotRoot())); $job->setDiskUsage($du); $this->info('Client "%clientid%", Job "%jobid%" du end.', array('%clientid%' => $job->getClient()->getId(), '%jobid%' => $job->getId()), $context); $job_run_size = $du - $du_before; // post script execution if needed if ($mustRunScripts) { foreach ($job->getPostScripts() as $script) { $stats['ELKARBACKUP_JOB_RUN_SIZE'] = $job_run_size; $stats['ELKARBACKUP_JOB_STARTTIME'] = $job_starttime; $stats['ELKARBACKUP_JOB_ENDTIME'] = $job_endtime; if ($this->runScript('post', $status, $job->getClient(), $job, $script, $stats)) { $this->info('Job "%jobid%" post script ok.', array('%jobid%' => $job->getId()), $context); } else { $this->err('Job "%jobid%" post script error.', array('%jobid%' => $job->getId()), $context); $warnings = True; } } } //tahoe backup $tahoe = $container->get('Tahoe'); $tahoeInstalled = $tahoe->isInstalled(); $tahoeOn = $container->getParameter('tahoe_active'); if ($tahoeInstalled && $tahoeOn) { $tahoe->enqueueJob($job, $retain); } } if (false === unlink($confFileName)) { $this->warn('Error unlinking config file %filename%.', array('%filename%' => $confFileName), $context); } if (True === $ok) { if (True === $warnings) { $ok = 2; } } return $ok; }
protected function _getJobTahoePath(Job $job) { $idClient = $job->getClient()->getId(); $idJob = $job->getId(); return 'elkarbackup:Backups/' . sprintf('%04d', $idClient) . '/' . sprintf('%04d', $idJob) . '/'; }