function postProcess(backupJob $job)
 {
     $scheduledBackup = $job->getScheduledBackup();
     // Get Params
     $sbParams = $scheduledBackup->getParameters();
     $this->validateParams($sbParams);
     // If maintain_materialized_copy is set and enabled, then we need to make sure we keep the latest restore available
     if (isset($sbParams['maintain_materialized_copy']) && $sbParams['maintain_materialized_copy'] == 1) {
         $this->infolog->write("Maintain materialized copy feature is enabled for this backup -- materializing latest backup ...", XBM_LOG_INFO);
         $job->setStatus('Materializing Latest');
         $manager = new materializedSnapshotManager();
         $manager->setInfoLogStream($this->infolog);
         $manager->setLogStream($this->log);
         $manager->materializeLatest($scheduledBackup);
         $this->infolog->write("Completed materializing latest backup.", XBM_LOG_INFO);
     }
     return true;
 }
 function applyRetentionPolicy(backupJob $job)
 {
     global $config;
     $scheduledBackup = $job->getScheduledBackup();
     if (!is_object($scheduledBackup)) {
         throw new Exception('fullonlyBackupTaker->applyRetentionPolicy: ' . "Error: This function requires a scheduledBackup object as a parameter.");
     }
     // Get the params/options for this scheduledBackup
     $params = $scheduledBackup->getParameters();
     // Validate them
     $this->validateParams($params);
     $sbGroups = array_reverse($scheduledBackup->getSnapshotGroupsNewestToOldest());
     // While we have too many - destroy the oldest snapshot
     while (sizeOf($sbGroups) > $params['max_snapshots']) {
         $this->infolog->write('There are more backups than the allowed maximum of ' . $params['max_snapshots'] . ', removing the oldest backup...', XBM_LOG_INFO);
         $snapshot = $sbGroups[0]->getSeed();
         $snapshot->destroy();
         $sbGroups = array_reverse($scheduledBackup->getSnapshotGroupsNewestToOldest());
     }
     return true;
 }
 function getNew(scheduledBackup $scheduledBackup)
 {
     $sbInfo = $scheduledBackup->getInfo();
     $conn = dbConnection::getInstance($this->log);
     $sql = "INSERT INTO backup_jobs (backup_job_id, start_time, status, scheduled_backup_id, pid ) VALUES " . "(NULL, NOW(), 'Initializing', " . $sbInfo['scheduled_backup_id'] . ", " . getmypid() . " )";
     if (!($res = $conn->query($sql))) {
         throw new DBException('backupJobGetter->getNew: ' . "Error: Query: {$sql} \nFailed with MySQL Error: {$conn->error}");
     }
     $job = new backupJob($conn->insert_id);
     $job->setLogStream($this->log);
     return $job;
 }
 function takeIncrementalBackupSnapshot(backupJob $job, $snapshotGroup, $seedSnap)
 {
     global $config;
     $scheduledBackup = $job->getScheduledBackup();
     /****************************
     	 		  TAKING INCREMENTAL BACKUP
     			****************************/
     // Create object for the lock...
     $runningBackup = new runningBackup();
     $runningBackup->setInfoLogStream($this->infolog);
     // Get scheduledBackup info
     $sbInfo = $scheduledBackup->getInfo();
     // Get scheduledBackup host
     $sbHost = $scheduledBackup->getHost();
     // get host info
     $hostInfo = $sbHost->getInfo();
     $mostRecentSnap = $snapshotGroup->getMostRecentCompletedBackupSnapshot();
     // Initialize a backup for sbHost for scheduledBackup
     $runningBackup->init($sbHost, $scheduledBackup);
     // Release our queue tickets
     $queueManager = new queueManager();
     $queueManager->setLogStream($this->log);
     foreach ($this->ticketsToReleaseOnStart as $ticket) {
         $queueManager->releaseTicket($ticket);
     }
     try {
         $lsn = $seedSnap->getLsn();
         // Create new object shell
         $snapshot = new backupSnapshot();
         // Init the snapshot here and use the ID for the tempdirname
         $snapshot->init($scheduledBackup, 'DELTA', 'INCREMENTAL', $snapshotGroup, $mostRecentSnap->id);
         // Get runningBackup info
         $rbInfo = $runningBackup->getInfo();
         // Start another TRY block so we can catch any exceptions and clean up our snapshot status.
         try {
             $snapshotInfo = $snapshot->getInfo();
             $tempDir = $runningBackup->getStagingTmpdir();
             // Build the command to run the snapshot into the staging dir
             $xbBinary = $scheduledBackup->getXtraBackupBinary();
             // Command should look like this:
             $xbCommand = "ssh -o StrictHostKeyChecking=no -p " . $hostInfo['ssh_port'] . " " . $sbInfo['backup_user'] . "@" . $hostInfo['hostname'] . " 'cd {$tempDir} ; innobackupex --ibbackup=" . $xbBinary . " --slave-info --incremental-lsn=" . $lsn . " " . $tempDir . "/deltas" . " --user="******" --safe-slave-backup " . " --password="******" --no-timestamp --incremental --throttle=" . $scheduledBackup->getXtraBackupThrottleValue() . " 1>&2 '";
             // Set up how we'll interact with the IO file handlers of the process
             $xbDescriptors = array(0 => array('file', '/dev/null', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'w'));
             // Connect to the remote host and create the backup into a staging directory then copy it back via netcat and tar
             ////////
             ////////
             // KICK OFF XTRABACKUP INCREMENTAL //
             ////////
             ////////
             // Set the state of the snapshot to RUNNING
             $snapshot->setStatus('RUNNING');
             // Info output
             $this->infolog->write("Staging an INCREMENTAL xtrabackup snapshot of " . $sbInfo['datadir_path'] . " via ssh: " . $sbInfo['backup_user'] . "@" . $hostInfo['hostname'] . " to " . $tempDir . "/deltas...", XBM_LOG_INFO);
             // DEBUG
             $this->infolog->write("Attempting to run the incremental backup with command:\n" . preg_replace('/--password=(.+?)\\s+/', '--password=XXXXXXX ', $xbCommand) . " \n", XBM_LOG_DEBUG);
             // Start the xtrabackup process
             $xbProc = proc_open($xbCommand, $xbDescriptors, $xbPipes);
             // Check that we launched OK.
             if (!is_resource($xbProc)) {
                 throw new Exception('genericBackupTaker->takeIncrementalBackupSnapshot: ' . "Error: Unable to use ssh to start xtrabackup with: {$xbCommand} .");
             }
             // Check the status of the backup every second...
             $streamContents = '';
             stream_set_blocking($xbPipes[2], 0);
             do {
                 $streamContents .= stream_get_contents($xbPipes[2]);
                 if (!($xbStatus = proc_get_status($xbProc))) {
                     throw new Exception('genericBackupTaker->takeIncrementalBackupSnapshot: ' . "Error: Unable to retrieve status on backup process.");
                 }
                 if ($job->isKilled()) {
                     throw new KillException('The backup was killed by an administrator.');
                 }
                 sleep(1);
             } while ($xbStatus['running']);
             if ($xbStatus['exitcode'] != 0) {
                 throw new Exception('genericBackupTaker->takeIncrementalBackupSnapshot: ' . "Error: There was an error backing up - The process returned code " . $xbStatus['exitcode'] . "." . " The output from the backup is as follows:\n" . $streamContents);
             }
             /*print_r($xbStatus);
             		echo "\nWe got STDOUT: \n";
             		echo stream_get_contents($xbPipes[1]);
             		echo "\nWe got STDERR: \n";
             		echo stream_get_contents($xbPipes[2]); */
             $this->infolog->write("XtraBackup completed staging the backup with the following output:\n" . $streamContents, XBM_LOG_INFO);
             // Copy it to local machine
             $path = $snapshot->getPath();
             // Fire up a netcat listener
             // Set the command we plan to run
             $ncBuilder = new netcatCommandBuilder();
             $ncServer = $ncBuilder->getServerCommand($rbInfo['port']);
             $ncLogfile = $config['LOGS']['logdir'] . '/hosts/' . $hostInfo['hostname'] . '.netcat.log';
             // Change to the dir where we want to put the files
             $ncCommand = ' cd ' . $path . ' ; ';
             // Check to see if there us a GNU tar - used to make XBM work on Solaris 11, since their tar doesn't work correctly
             $ncCommand .= ' if [ -f /usr/gnu/bin/tar ]; then TAR="/usr/gnu/bin/tar"; else TAR=tar; fi; ';
             // Now start the netcat listener and pipe through the auto-detected tar command
             $ncCommand .= $ncServer . ' | $TAR xvf - >> ' . $ncLogfile . ' 2>&1';
             // Open the process with a stream to read from it
             // Set up how we'll interact with the IO file handlers of the process
             $ncDescriptors = array(0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'w'));
             // Open the netcat listener proc
             $this->infolog->write("Attempting to run netcat with command: " . $ncCommand, XBM_LOG_DEBUG);
             $ncProc = proc_open($ncCommand, $ncDescriptors, $ncPipes);
             if (!is_resource($ncProc)) {
                 throw new Exception('genericBackupTaker->takeIncrementalBackupSnapshot: ' . "Error: Unable to start netcat with command: {$ncCommand} .");
             }
             // Info output
             $this->infolog->write("Started Netcat (nc) listener on port " . $rbInfo['port'] . " to receive backup tar stream into directory {$path} ...", XBM_LOG_INFO);
             $ncClient = $ncBuilder->getClientCommand($config['SYSTEM']['xbm_hostname'], $rbInfo['port']);
             // Copy the backup back via the netcat listener
             $copyCommand = "ssh -o StrictHostKeyChecking=no -p " . $hostInfo['ssh_port'] . " " . $sbInfo['backup_user'] . "@" . $hostInfo['hostname'] . " 'cd " . $tempDir . "/deltas; tar cvf - . | " . $ncClient . " '";
             // Set the state of the snapshot to COPYING
             $snapshot->setStatus('COPYING');
             // Set up how we'll interact with the IO file handlers of the process
             $copyDescriptors = array(0 => array('file', '/dev/null', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'w'));
             // Start the xtrabackup process
             $this->infolog->write("Attempting to run copy with command: " . $copyCommand, XBM_LOG_DEBUG);
             $copyProc = proc_open($copyCommand, $copyDescriptors, $copyPipes);
             // Check that we launched OK.
             if (!is_resource($copyProc)) {
                 throw new Exception('genericBackupTaker->takeIncrementalBackupSnapshot: ' . "Error: Unable to use ssh to start copy with: {$copyCommand} .");
             }
             // Check the status of the backup every second...
             $streamContents = '';
             stream_set_blocking($copyPipes[2], 0);
             do {
                 $streamContents .= stream_get_contents($copyPipes[2]);
                 if (!($copyStatus = proc_get_status($copyProc))) {
                     throw new Exception('genericBackupTaker->takeIncrementalBackupSnapshot: ' . "Error: Unable to retrieve status on copy process.");
                 }
                 if ($job->isKilled()) {
                     throw new KillException('The backup was killed by an administrator.');
                 }
                 sleep(1);
             } while ($copyStatus['running']);
             if ($copyStatus['exitcode'] != 0) {
                 throw new Exception('genericBackupTaker->takeIncrementalBackupSnapshot: ' . "Error: There was an error copying files - The process returned code " . $copyStatus['exitcode'] . "." . " The output from the backup is as follows:\n" . $streamContents);
             }
             /* For debugging...
             			print_r($copyStatus);
             			echo "\nWe got STDOUT: \n";
             			echo stream_get_contents($copyPipes[1]);
             			echo "\nWe got STDERR: \n";
             			echo stream_get_contents($copyPipes[2]); 
             			*/
             // Close out the copy and netcat processes
             proc_close($copyProc);
             proc_close($ncProc);
             // Set the snapshot time to be now
             $snapshot->setSnapshotTime(date('Y-m-d H:i:s'));
             // Set the state of the snapshot to COMPLETED
             $snapshot->setStatus('COMPLETED');
             $this->infolog->write("Completed copying the backup via netcat with the following output:\n" . $streamContents, XBM_LOG_INFO);
         } catch (Exception $e) {
             if (get_class($e) == 'KillException') {
                 $this->infolog->write("The backup job was killed by an administrator. Aborting...", XBM_LOG_ERROR);
             }
             // If we had a netcat process, check to see if we need to kill it/clean up
             if (isset($ncProc) && is_resource($ncProc)) {
                 proc_terminate($ncProc);
             }
             // Remove the snapshot files and mark it as failed.
             if ($config['SYSTEM']['cleanup_on_failure'] == true) {
                 $this->infolog->write("Cleaning up files...", XBM_LOG_INFO);
                 $snapshot->deleteFiles();
             } else {
                 $this->infolog->write("Skipping cleanup as cleanup_on_failure is turned off...", XBM_LOG_INFO);
             }
             $snapshot->setStatus('FAILED');
             throw $e;
         }
     } catch (Exception $e) {
         // Clean up the running backup entry and rethrow error..
         $runningBackup->finish();
         throw $e;
     }
     // Clean up after ourselves..
     // release our lock on the netcat port, scheduled backup, etc.
     $runningBackup->finish();
     return $snapshot;
 }
 function postProcess(backupJob $job)
 {
     $scheduledBackup = $job->getScheduledBackup();
     // Validate
     if ($scheduledBackup === false || !is_object($scheduledBackup)) {
         throw new Exception('continuousIncrementalBackupTaker->postProcess: ' . "Error: Expected a scheduledBackup object to be passed as a parameter, but did not get one.");
     }
     // Get Params
     $sbParams = $scheduledBackup->getParameters();
     $this->validateParams($sbParams);
     // If maintain_materialized_copy is set and enabled, then we need to make sure we keep the latest restore available
     if (isset($sbParams['maintain_materialized_copy']) && $sbParams['maintain_materialized_copy'] == 1) {
         $this->infolog->write("Maintain materialized copy feature is enabled for this backup -- materializing latest backup ...", XBM_LOG_INFO);
         $job->setStatus('Materializing Latest');
         $manager = new materializedSnapshotManager();
         $manager->setInfoLogStream($this->infolog);
         $manager->setLogStream($this->log);
         $manager->materializeLatest($scheduledBackup);
         $this->infolog->write("Completed materializing latest backup.", XBM_LOG_INFO);
     }
     return true;
 }