function getChild() { global $config; if (!is_numeric($this->id)) { throw new Exception('backupSnapshot->getChild: ' . "Error: The ID for this object is not an integer."); } $conn = dbConnection::getInstance($this->log); $sql = "SELECT backup_snapshot_id FROM backup_snapshots WHERE status='COMPLETED' AND parent_snapshot_id=" . $this->id; if (!($res = $conn->query($sql))) { throw new Exception('backupSnapshot->getChild: ' . "Error: Query: {$sql} \nFailed with MySQL Error: {$conn->error}"); } if ($res->num_rows != 1) { throw new Exception('backupSnapshot->getChild: ' . "Error: Could not identify a single child of this backupSnapshot."); } $row = $res->fetch_array(); $backupGetter = new backupSnapshotGetter(); return $backupGetter->getById($row['backup_snapshot_id']); }
function getBackupSnapshot() { $this->__validate(); $info = $this->getInfo(); $backupSnapshotGetter = new backupSnapshotGetter(); $this->backupSnapshot = $backupSnapshotGetter->getById($info['backup_snapshot_id']); return $this->backupSnapshot; }
function handleSnapshotActions($args) { global $config; if (!isset($args[2])) { // Just output some helpful info and exit echo "Error: Action missing.\n\n"; $this->printSnapshotHelpText($args); return; } switch ($args[2]) { // Handle list case 'list': // If we just get a hostname, check to see if it only has one Scheduled Backup task if (isset($args[3]) && !isset($args[4])) { $hostname = $args[3]; $hostGetter = new hostGetter(); $hostGetter->setLogStream($this->log); if (!($host = $hostGetter->getByName($hostname))) { throw new ProcessingException("Error: Could not find a host with hostname: {$hostname}"); } $scheduledBackups = $host->getScheduledBackups(); // If we dont find scheduled backups - throw exception if (sizeOf($scheduledBackups) == 0) { throw new ProcessingException("Error: Could not find any backups for host: {$hostname}"); } } // If we are dealing with only one specific backup if (isset($args[3]) && isset($args[4])) { $scheduledBackupGetter = new scheduledBackupGetter(); $scheduledBackupGetter->setLogStream($this->log); $hostname = $args[3]; $backupName = $args[4]; $scheduledBackups = array(); if (!($scheduledBackups[0] = $scheduledBackupGetter->getByHostnameAndName($hostname, $backupName))) { throw new ProcessingException("Error: Could not find a backup for host: {$hostname} with name: {$backupName}"); } } if (!isset($args[3]) && !isset($args[4])) { throw new InputException("Error: Not all required parameters for the snapshots to list were given.\n\n" . " Syntax:\n\n\txbm " . $args[1] . " list <hostname> [<backup_name>]\n\n" . " Example:\n\n\txbm " . $args[1] . " list db01.mydomain.com 'Nightly Backup'\n\n"); } echo "-- Listing Backup Snapshots for {$hostname} --\n\n"; // By this point we should have an array scheduledBackups to display info for foreach ($scheduledBackups as $scheduledBackup) { $sbInfo = $scheduledBackup->getInfo(); $groups = $scheduledBackup->getSnapshotGroupsNewestToOldest(); $strategy = $scheduledBackup->getBackupStrategy(); $strategyInfo = $strategy->getInfo(); echo " -- Snapshots for Backup Name: " . $sbInfo['name'] . "\n"; // Display materialized snapshot if enabled $params = $scheduledBackup->getParameters(); if (isset($params['maintain_materialized_copy']) && $params['maintain_materialized_copy'] == 1) { $materialized = $scheduledBackup->getMostRecentCompletedMaterializedSnapshot(); echo "\t-- Latest Materialized Snapshot:\n"; if ($materialized == false) { echo "\t None.\n"; } else { $materializedInfo = $materialized->getInfo(); $mSnap = $materialized->getBackupSnapshot(); $mSnapInfo = $mSnap->getInfo(); echo "\t ID: m" . $materializedInfo['materialized_snapshot_id'] . " Snapshot Time: " . $mSnapInfo['snapshot_time']; // Was going to display path here, but decided users should never know the path // they should always use xbm commands for restores to ensure correct locking //." Path: ".$materialized->getPath()."\n"); } } // Display Snapshots (by group if ROTATING method is used) $groupNum = 0; foreach ($groups as $group) { $groupNum++; if ($strategyInfo['strategy_code'] == 'ROTATING') { echo "\t-- Group: {$groupNum}\n"; } $snapshots = $group->getAllSnapshotsNewestToOldest(); foreach ($snapshots as $snapshot) { $snapInfo = $snapshot->getInfo(); echo "\t ID: " . $snapInfo['backup_snapshot_id'] . " Type: " . $snapInfo['type'] . " Snapshot Time: " . $snapInfo['snapshot_time'] . " Creation Method: " . $snapInfo['creation_method'] . "\n"; } if (sizeOf($snapshots) == 0) { echo "\t None.\n"; } } } echo "\n\n"; break; // Handle restore // Handle restore case 'restore-latest': // If we just got a path and hostname, if (isset($args[3]) && isset($args[4]) && !isset($args[5])) { $hostname = $args[4]; $targetPath = $args[3]; $hostGetter = new hostGetter(); $hostGetter->setLogStream($this->log); if (!($host = $hostGetter->getByName($hostname))) { throw new ProcessingException("Error: Could not find a host with hostname: {$hostname}"); } $scheduledBackups = $host->getScheduledBackups(); // If we dont find scheduled backups - throw exception if (sizeOf($scheduledBackups) == 0) { throw new ProcessingException("Error: Could not find any backups for host: {$hostname}"); } // If we find more than 1 scheduled backup - throw exception if (sizeOf($scheduledBackups) > 1) { throw new ProcessingException("Error: Found multiple Backup Tasks for host: {$hostname} - Please specify which backup name to restore the latest snapshot for."); } $scheduledBackup = $scheduledBackups[0]; } // If we got a host AND backup name if (isset($args[3]) && isset($args[4]) && isset($args[5])) { $targetPath = $args[3]; $hostname = $args[4]; $backupName = $args[5]; $scheduledBackupGetter = new scheduledBackupGetter(); $scheduledBackupGetter->setLogStream($this->log); if (!($scheduledBackup = $scheduledBackupGetter->getByHostnameAndName($hostname, $backupName))) { throw new ProcessingException("Error: Could not find a Scheduled Backup Task for host: {$hostname} with name: {$backupName}"); } } if (!isset($args[3]) || !isset($args[4])) { throw new InputException("Error: Not all required parameters for the Scheduled Backup you wish to restore the latest snapshot for were given.\n\n" . " Syntax:\n\n\txbm " . $args[1] . " restore-latest <target_path> <hostname> [<backup_name>]\n\n" . " Example:\n\n\txbm " . $args[1] . " restore-latest /restores/myrestore db01.mydomain.com 'Nightly Backup'\n\n"); } $sbInfo = $scheduledBackup->getInfo(); // Check if we have any COMPLETED snapshots anyway $snapCount = $scheduledBackup->getCompletedSnapshotCount(); if ($snapCount < 1) { throw new ProcessingException("Error: No snapshots exist for the Scheduled Backup Task with name: " . $sbInfo['name'] . " for host: {$hostname}"); } // We have a scheduledBackup - figure out if we might have a materialized snapshot and work accordingly $params = $scheduledBackup->getParameters(); $snapshot = false; if ($params['maintain_materialized_copy'] == 1) { // Is there a materialized snapshot? $snapshot = $scheduledBackup->getMostRecentCompletedMaterializedSnapshot(); } // If not, lets try finding the most recent snapshot for this scheduledBackup if ($snapshot == false) { $snapshot = $scheduledBackup->getMostRecentCompletedBackupSnapshot(); } // At this point we either have a materialized snapshot or regular snapshot in $snapshot // Lets proceed with restoring... $this->handleRestore($snapshot, $targetPath); break; case 'restore': if (isset($args[3]) && isset($args[4])) { // Handle the valid snapshot id inputs that we know // Numeric - regular snapshot if (is_numeric($args[4])) { $backupSnapshotGetter = new backupSnapshotGetter(); $backupSnapshotGetter->setLogStream($this->log); if (!($snapshot = $backupSnapshotGetter->getById($args[4]))) { throw new ProcessingException("Error: Could not find a Backup Snapshot with ID: " . $args[4]); } // Materialized snapshot } elseif (substr($args[4], 0, 1) == 'm' && is_numeric(substr($args[4], 1))) { $materialId = substr($args[4], 1); $materializedSnapshotGetter = new materializedSnapshotGetter(); $materializedSnapshotGetter->setLogStream($this->log); if (!($snapshot = $materializedSnapshotGetter->getById($materialId))) { throw new ProcessingException("Error: Could not find a materialized Backup Snapshot with ID: " . $args[4]); } // Catch all for when the input snapshot id is not recognized... // it should have been one of the following: // letter m, followed by numeric ID - eg. m12 - m signifies a materialized snapshot // just a numeric id - eg. 12 - no letter m prepended signifies a regular snapshot } else { throw new InputException("Error: The Snapshot ID specified must be of any of these forms: 12, m12 (m denotes a Materialized Snapshot ID)\n\n" . " Syntax:\n\n\txbm " . $args[1] . " restore <snapshot_id> <target_path>\n\n" . " Example:\n\n\txbm " . $args[1] . " restore m21 /restores/myrestore\n\n"); } $snapInfo = $snapshot->getInfo(); if ($snapInfo['status'] != 'COMPLETED') { throw new ProcessingException("Error: The snapshot specified is in " . $snapInfo['status'] . " status. Only COMPLETED snapshots can be restored."); } $this->handleRestore($snapshot, $args[3]); } else { throw new InputException("Error: Not all required parameters for the restore action were given.\n\n" . " Syntax:\n\n\txbm " . $args[1] . " restore <snapshot_idt> <target_path>\n\n" . " Example:\n\n\txbm " . $args[1] . " restore m21 /restores/myrestore\n\n"); } break; // Catch unknown action // Catch unknown action default: echo "Error: Unrecognized action for " . $args[1] . " context: " . $args[2] . "\n\n"; $this->printSnapshotHelpText($args); break; } }
function getMostRecentCompletedBackupSnapshot() { global $config; if (!is_numeric($this->id)) { throw new Exception('scheduledBackup->getMostRecentCompletedBackupSnapshot: ' . "Error: The ID for this object is not an integer."); } $conn = dbConnection::getInstance($this->log); $sql = "SELECT backup_snapshot_id FROM backup_snapshots WHERE status='COMPLETED' AND scheduled_backup_id=" . $this->id . " ORDER BY snapshot_time DESC LIMIT 1"; if (!($res = $conn->query($sql))) { throw new Exception('scheduledBackup->getMostRecentCompletedBackupSnapshot: ' . "Error: Query: {$sql} \nFailed with MySQL Error: {$conn->error}"); } if ($res->num_rows != 1) { throw new Exception('scheduledBackup->getMostRecentCompletedBackupSnapshot: ' . "Error: Could not find the most recent backup snapshot for Scheduled Backup ID " . $this->id); } $row = $res->fetch_array(); $snapshotGetter = new backupSnapshotGetter(); $snapshot = $snapshotGetter->getById($row['backup_snapshot_id']); return $snapshot; }
function getAllSnapshotsNewestToOldest() { $this->__validate(); global $config; $conn = dbConnection::getInstance($this->log); $sql = "SELECT backup_snapshot_id FROM backup_snapshots WHERE status='COMPLETED' AND scheduled_backup_id=" . $this->scheduledBackupId . " \n\t\t\t\t\tAND snapshot_group_num=" . $this->snapshotGroupNum . " ORDER BY snapshot_time DESC"; if (!($res = $conn->query($sql))) { throw new Exception('backupSnapshotGroup->getAllSnapshotsNewestToOldest: ' . "Error: Query: {$sql} \nFailed with MySQL Error: {$conn->error}"); } $snapshots = array(); while ($row = $res->fetch_array()) { $snapshotGetter = new backupSnapshotGetter(); $snapshots[] = $snapshotGetter->getById($row['backup_snapshot_id']); } return $snapshots; }
function applyRetentionPolicy(backupJob $job) { global $config; $scheduledBackup = $job->getScheduledBackup(); $this->infolog->write("Checking to see if any snapshots need to be merged into the seed backup.", XBM_LOG_INFO); if (!is_object($scheduledBackup)) { throw new Exception('continuousIncrementalBackupTaker->applyRetentionPolicy: ' . "Error: This function requires a scheduledBackup object as a parameter."); } $conn = dbConnection::getInstance($this->log); $sql = "SELECT backup_snapshot_id FROM backup_snapshots WHERE status='COMPLETED' AND scheduled_backup_id=" . $scheduledBackup->id . " AND snapshot_time IS NOT NULL ORDER BY snapshot_time ASC"; if (!($res = $conn->query($sql))) { throw new Exception('continuousIncrementalBackupTaker->applyRetentionPolicy: ' . "Error: Query: {$sql} \nFailed with MySQL Error: {$conn->error}"); } // Get info for this scheduledBackup $info = $scheduledBackup->getInfo(); // Get the params/options for this scheduledBackup $params = $scheduledBackup->getParameters(); // Validate them $this->validateParams($params); // Build service objects for later use $snapshotGetter = new backupSnapshotGetter(); $snapshotMerger = new backupSnapshotMerger(); // Check to see if the number of rows we have is more than the number of snapshots we should have at a max while ($res->num_rows > $params['max_snapshots']) { // Grab the first row - it is the SEED if (!($row = $res->fetch_array())) { throw new Exception('continuousIncrementalBackupTaker->applyRetentionPolicy: ' . "Error: Could not retrieve the object ID for the seed of Scheduled Backup ID " . $scheduledBackup->id); } $seedSnapshot = $snapshotGetter->getById($row['backup_snapshot_id']); // Grab the second row - it is the DELTA to be collapsed. if (!($row = $res->fetch_array())) { throw new Exception('continuousIncrementalBackupTaker->applyRetentionPolicy: ' . "Error: Could not retrieve the object ID for the seed of Scheduled Backup ID " . $scheduledBackup->id); } $deltaSnapshot = $snapshotGetter->getById($row['backup_snapshot_id']); $this->infolog->write("Merging deltas in Backup Snapshot ID #" . $deltaSnapshot->id . " with Backup Snapshot ID #" . $seedSnapshot->id . ".", XBM_LOG_INFO); // Merge them together $snapshotMerger->mergeSnapshots($seedSnapshot, $deltaSnapshot); // Check to see what merge work is needed now. $sql = "SELECT backup_snapshot_id FROM backup_snapshots WHERE status='COMPLETED' AND scheduled_backup_id=" . $scheduledBackup->id . " AND snapshot_time IS NOT NULL ORDER BY snapshot_time ASC"; if (!($res = $conn->query($sql))) { throw new Exception('continuousIncrementalBackupTaker->applyRetentionPolicy: ' . "Error: Query: {$sql} \nFailed with MySQL Error: {$conn->error}"); } } return true; }