/** * @param array $data * @param Form $form * * @return SS_HTTPResponse */ public function doPostSnapshot($data, $form) { $this->setCurrentActionType(self::ACTION_SNAPSHOT); $project = $this->getCurrentProject(); if (!$project) { return $this->project404Response(); } $validEnvs = $project->DNEnvironmentList()->filterByCallback(function ($item) { return $item->canUploadArchive(); }); // Validate $data['EnvironmentID'] by checking against $validEnvs. $environment = $validEnvs->find('ID', $data['EnvironmentID']); if (!$environment) { throw new LogicException('Invalid environment'); } $dataArchive = DNDataArchive::create(array('UploadToken' => DNDataArchive::generate_upload_token())); $form->saveInto($dataArchive); $dataArchive->write(); return $this->redirect(Controller::join_links($project->Link(), 'postsnapshotsuccess', $dataArchive->ID)); }
/** * Backs up database and/or assets to a designated folder, * and packs up the files into a single sspak. * * @param DNDataTransfer $dataTransfer * @param DeploynautLogFile $log */ protected function dataTransferBackup(DNDataTransfer $dataTransfer, DeploynautLogFile $log) { $environment = $dataTransfer->Environment(); $name = $environment->getFullName(); // Associate a new archive with the transfer. // Doesn't retrieve a filepath just yet, need to generate the files first. $dataArchive = DNDataArchive::create(); $dataArchive->Mode = $dataTransfer->Mode; $dataArchive->AuthorID = $dataTransfer->AuthorID; $dataArchive->OriginalEnvironmentID = $environment->ID; $dataArchive->EnvironmentID = $environment->ID; $dataArchive->IsBackup = $dataTransfer->IsBackupDataTransfer(); // Generate directory structure with strict permissions (contains very sensitive data) $filepathBase = $dataArchive->generateFilepath($dataTransfer); mkdir($filepathBase, 0700, true); $databasePath = $filepathBase . DIRECTORY_SEPARATOR . 'database.sql'; // Backup database if (in_array($dataTransfer->Mode, array('all', 'db'))) { $log->write(sprintf('Backup of database from "%s" started', $name)); $command = $this->getCommand('data:getdb', 'db', $environment, array('data_path' => $databasePath), $log); $command->run(function ($type, $buffer) use($log) { $log->write($buffer); }); if (!$command->isSuccessful()) { $this->extend('dataTransferFailure', $environment, $log); throw new RuntimeException($command->getErrorOutput()); } $log->write(sprintf('Backup of database from "%s" done', $name)); } // Backup assets if (in_array($dataTransfer->Mode, array('all', 'assets'))) { $log->write(sprintf('Backup of assets from "%s" started', $name)); $command = $this->getCommand('data:getassets', 'web', $environment, array('data_path' => $filepathBase), $log); $command->run(function ($type, $buffer) use($log) { $log->write($buffer); }); if (!$command->isSuccessful()) { $this->extend('dataTransferFailure', $environment, $log); throw new RuntimeException($command->getErrorOutput()); } $log->write(sprintf('Backup of assets from "%s" done', $name)); } $sspakFilename = sprintf('%s.sspak', $dataArchive->generateFilename($dataTransfer)); $sspakFilepath = $filepathBase . DIRECTORY_SEPARATOR . $sspakFilename; try { $dataArchive->attachFile($sspakFilepath, $dataTransfer); $dataArchive->setArchiveFromFiles($filepathBase); } catch (Exception $e) { $log->write($e->getMessage()); throw new RuntimeException($e->getMessage()); } // Remove any assets and db files lying around, they're not longer needed as they're now part // of the sspak file we just generated. Use --force to avoid errors when files don't exist, // e.g. when just an assets backup has been requested and no database.sql exists. $process = new Process(sprintf('rm -rf %s/assets && rm -f %s', $filepathBase, $databasePath)); $process->run(); if (!$process->isSuccessful()) { $log->write('Could not delete temporary files'); throw new RuntimeException($process->getErrorOutput()); } $log->write(sprintf('Creating sspak file done: %s', $dataArchive->ArchiveFile()->getAbsoluteURL())); }
/** * Backs up database and/or assets to a designated folder, * and packs up the files into a single sspak. * * @param DNDataTransfer $dataTransfer * @param DeploynautLogFile $log */ protected function dataTransferBackup(DNDataTransfer $dataTransfer, DeploynautLogFile $log) { $environmentObj = $dataTransfer->Environment(); $project = $environmentObj->Project(); $projectName = $project->Name; $environmentName = $environmentObj->Name; $env = $project->getProcessEnv(); $project = DNProject::get()->filter('Name', $projectName)->first(); $name = $projectName . ':' . $environmentName; // Associate a new archive with the transfer. // Doesn't retrieve a filepath just yet, need to generate the files first. $dataArchive = DNDataArchive::create(); $dataArchive->Mode = $dataTransfer->Mode; $dataArchive->AuthorID = $dataTransfer->AuthorID; $dataArchive->OriginalEnvironmentID = $dataTransfer->Environment()->ID; $dataArchive->EnvironmentID = $dataTransfer->Environment()->ID; $dataArchive->IsBackup = $dataTransfer->IsBackupDataTransfer(); // Generate directory structure with strict permissions (contains very sensitive data) $filepathBase = $dataArchive->generateFilepath($dataTransfer); mkdir($filepathBase, 0700, true); $databasePath = $filepathBase . DIRECTORY_SEPARATOR . 'database.sql'; // Backup database if (in_array($dataTransfer->Mode, array('all', 'db'))) { $log->write('Backup of database from "' . $name . '" started'); $args = array('data_path' => $databasePath); $command = $this->getCommand("data:getdb", 'db', $name, $args, $env, $log); $command->run(function ($type, $buffer) use($log) { $log->write($buffer); }); if (!$command->isSuccessful()) { throw new RuntimeException($command->getErrorOutput()); } $log->write('Backup of database from "' . $name . '" done'); } // Backup assets if (in_array($dataTransfer->Mode, array('all', 'assets'))) { $log->write('Backup of assets from "' . $name . '" started'); $args = array('data_path' => $filepathBase); $command = $this->getCommand("data:getassets", 'web', $name, $args, $env, $log); $command->run(function ($type, $buffer) use($log) { $log->write($buffer); }); if (!$command->isSuccessful()) { throw new RuntimeException($command->getErrorOutput()); } $log->write('Backup of assets from "' . $name . '" done'); } $log->write('Creating *.sspak file'); $sspakFilename = sprintf('%s.sspak', $dataArchive->generateFilename($dataTransfer)); $sspakCmd = sprintf('cd %s && sspak saveexisting %s 2>&1', $filepathBase, $sspakFilename); if ($dataTransfer->Mode == 'db') { $sspakCmd .= sprintf(' --db=%s', $databasePath); } elseif ($dataTransfer->Mode == 'assets') { $sspakCmd .= sprintf(' --assets=%s/assets', $filepathBase); } else { $sspakCmd .= sprintf(' --db=%s --assets=%s/assets', $databasePath, $filepathBase); } $process = new Process($sspakCmd); $process->setTimeout(3600); $process->run(); if (!$process->isSuccessful()) { $log->write('Could not package the backup via sspak'); throw new RuntimeException($process->getErrorOutput()); } // HACK: find_or_make() expects path relative to assets/ $sspakFilepath = ltrim(str_replace(array(ASSETS_PATH, realpath(ASSETS_PATH)), '', $filepathBase . DIRECTORY_SEPARATOR . $sspakFilename), DIRECTORY_SEPARATOR); try { $folder = Folder::find_or_make(dirname($sspakFilepath)); $file = new File(); $file->Name = $sspakFilename; $file->Filename = $sspakFilepath; $file->ParentID = $folder->ID; $file->write(); // "Status" will be updated by the job execution $dataTransfer->write(); // Get file hash to ensure consistency. // Only do this when first associating the file since hashing large files is expensive. $dataArchive->ArchiveFileHash = md5_file($file->FullPath); $dataArchive->ArchiveFileID = $file->ID; $dataArchive->DataTransfers()->add($dataTransfer); $dataArchive->write(); } catch (Exception $e) { $log->write('Failed to add sspak file: ' . $e->getMessage()); throw new RuntimeException($e->getMessage()); } // Remove any assets and db files lying around, they're not longer needed as they're now part // of the sspak file we just generated. Use --force to avoid errors when files don't exist, // e.g. when just an assets backup has been requested and no database.sql exists. $process = new Process(sprintf('rm -rf %s/assets && rm -f %s', $filepathBase, $databasePath)); $process->run(); if (!$process->isSuccessful()) { $log->write('Could not delete temporary files'); throw new RuntimeException($process->getErrorOutput()); } $log->write(sprintf('Creating *.sspak file done: %s', $file->getAbsoluteURL())); }
public function testCanMoveTo() { $samantha = $this->objFromFixture('Member', 'project1-samantha'); $sarah = $this->objFromFixture('Member', 'project1-sarah'); $eva = $this->objFromFixture('Member', 'eva'); $uat1 = $this->objFromFixture('DNEnvironment', 'project1-uat'); $live1 = $this->objFromFixture('DNEnvironment', 'project1-live'); $uat2 = $this->objFromFixture('DNEnvironment', 'project2-uat'); $live2 = $this->objFromFixture('DNEnvironment', 'project2-live'); $archive = DNDataArchive::create(); $archive->EnvironmentID = $uat1->ID; $archive->write(); // Samantha doesn't have upload permission to live1. $this->assertFalse($archive->canMoveTo($live1, $samantha)); // Cross-project moves are forbidden. $this->assertFalse($archive->canMoveTo($uat2, $samantha)); // Eva has upload permission to live1. $this->assertTrue($archive->canMoveTo($live1, $eva)); // Cross-project moves are forbidden. $this->assertFalse($archive->canMoveTo($uat2, $eva)); // Sarah has upload permission to live1, but not download to uat1. $this->assertFalse($archive->canMoveTo($live1, $sarah)); }
public function doPostSnapshot($data, $form) { $project = $this->getCurrentProject(); if (!$project) { return new SS_HTTPResponse("Project '" . Convert::raw2xml($this->getRequest()->latestParam('Project')) . "' not found.", 404); } $validEnvs = $project->DNEnvironmentList()->filterByCallback(function ($item) { return $item->canUploadArchive(); }); // Validate $data['EnvironmentID'] by checking against $validEnvs. $environment = $validEnvs->find('ID', $data['EnvironmentID']); if (!$environment) { throw new LogicException('Invalid environment'); } $dataArchive = DNDataArchive::create(array('UploadToken' => DNDataArchive::generate_upload_token())); $form->saveInto($dataArchive); $dataArchive->write(); return $this->redirect(Controller::join_links($project->Link(), 'postsnapshotsuccess', $dataArchive->ID)); }
public function testValidateArchiveContentsFileMissingFails() { $archive = DNDataArchive::create(); $filename = __DIR__ . '/sspaks/not.found.sspak'; $archive->ArchiveFile()->Filename = $filename; $result = $archive->validateArchiveContents('all'); $this->assertFalse($result->valid()); $this->assertEquals('SSPak file "' . $filename . '" cannot be read.', current($result->messageList())); }