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 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 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 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; }