1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-17 20:32:41 +01:00

Add a "filePHID" to HarbormasterBuildLog and copy logs into Files during finalization

Summary: Depends on D19131. Ref T13088. During log finalization, stream the log into Files to support "Download Log", archive to Files, and API access.

Test Plan: Ran `write-log` and `rebuild-log`, saw Files objects generate with log content and appropriate permissions.

Subscribers: PHID-OPKG-gm6ozazyms6q6i22gyam

Maniphest Tasks: T13088

Differential Revision: https://secure.phabricator.com/D19132
This commit is contained in:
epriestley 2018-02-22 18:22:59 -08:00
parent 32c6b649dd
commit 8a2604cf06
8 changed files with 153 additions and 23 deletions

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_harbormaster.harbormaster_buildlog
ADD filePHID VARBINARY(64);

View file

@ -1309,6 +1309,7 @@ phutil_register_library_map(array(
'HarbormasterLogWorker' => 'applications/harbormaster/worker/HarbormasterLogWorker.php', 'HarbormasterLogWorker' => 'applications/harbormaster/worker/HarbormasterLogWorker.php',
'HarbormasterManagementArchiveLogsWorkflow' => 'applications/harbormaster/management/HarbormasterManagementArchiveLogsWorkflow.php', 'HarbormasterManagementArchiveLogsWorkflow' => 'applications/harbormaster/management/HarbormasterManagementArchiveLogsWorkflow.php',
'HarbormasterManagementBuildWorkflow' => 'applications/harbormaster/management/HarbormasterManagementBuildWorkflow.php', 'HarbormasterManagementBuildWorkflow' => 'applications/harbormaster/management/HarbormasterManagementBuildWorkflow.php',
'HarbormasterManagementRebuildLogWorkflow' => 'applications/harbormaster/management/HarbormasterManagementRebuildLogWorkflow.php',
'HarbormasterManagementRestartWorkflow' => 'applications/harbormaster/management/HarbormasterManagementRestartWorkflow.php', 'HarbormasterManagementRestartWorkflow' => 'applications/harbormaster/management/HarbormasterManagementRestartWorkflow.php',
'HarbormasterManagementUpdateWorkflow' => 'applications/harbormaster/management/HarbormasterManagementUpdateWorkflow.php', 'HarbormasterManagementUpdateWorkflow' => 'applications/harbormaster/management/HarbormasterManagementUpdateWorkflow.php',
'HarbormasterManagementWorkflow' => 'applications/harbormaster/management/HarbormasterManagementWorkflow.php', 'HarbormasterManagementWorkflow' => 'applications/harbormaster/management/HarbormasterManagementWorkflow.php',
@ -6614,6 +6615,7 @@ phutil_register_library_map(array(
'HarbormasterLogWorker' => 'HarbormasterWorker', 'HarbormasterLogWorker' => 'HarbormasterWorker',
'HarbormasterManagementArchiveLogsWorkflow' => 'HarbormasterManagementWorkflow', 'HarbormasterManagementArchiveLogsWorkflow' => 'HarbormasterManagementWorkflow',
'HarbormasterManagementBuildWorkflow' => 'HarbormasterManagementWorkflow', 'HarbormasterManagementBuildWorkflow' => 'HarbormasterManagementWorkflow',
'HarbormasterManagementRebuildLogWorkflow' => 'HarbormasterManagementWorkflow',
'HarbormasterManagementRestartWorkflow' => 'HarbormasterManagementWorkflow', 'HarbormasterManagementRestartWorkflow' => 'HarbormasterManagementWorkflow',
'HarbormasterManagementUpdateWorkflow' => 'HarbormasterManagementWorkflow', 'HarbormasterManagementUpdateWorkflow' => 'HarbormasterManagementWorkflow',
'HarbormasterManagementWorkflow' => 'PhabricatorManagementWorkflow', 'HarbormasterManagementWorkflow' => 'PhabricatorManagementWorkflow',

View file

@ -0,0 +1,54 @@
<?php
final class HarbormasterManagementRebuildLogWorkflow
extends HarbormasterManagementWorkflow {
protected function didConstruct() {
$this
->setName('rebuild-log')
->setExamples('**rebuild-log** --id __id__ [__options__]')
->setSynopsis(
pht(
'Rebuild the file and summary for a log. This is primarily '.
'intended to make it easier to develop new log summarizers.'))
->setArguments(
array(
array(
'name' => 'id',
'param' => 'id',
'help' => pht('Log to rebuild.'),
),
));
}
public function execute(PhutilArgumentParser $args) {
$viewer = $this->getViewer();
$log_id = $args->getArg('id');
if (!$log_id) {
throw new PhutilArgumentUsageException(
pht('Choose a build log to rebuild with "--id".'));
}
$log = id(new HarbormasterBuildLogQuery())
->setViewer($viewer)
->withIDs(array($log_id))
->executeOne();
if (!$log) {
throw new PhutilArgumentUsageException(
pht(
'Unable to load build log "%s".',
$log_id));
}
PhabricatorWorker::setRunAllTasksInProcess(true);
$log->scheduleRebuild(true);
echo tsprintf(
"%s\n",
pht('Done.'));
return 0;
}
}

View file

@ -7,14 +7,16 @@ final class HarbormasterManagementWriteLogWorkflow
$this $this
->setName('write-log') ->setName('write-log')
->setExamples('**write-log** --target __id__ [__options__]') ->setExamples('**write-log** --target __id__ [__options__]')
->setSynopsis(pht('Write a new Harbormaster build log.')) ->setSynopsis(
pht(
'Write a new Harbormaster build log. This is primarily intended '.
'to make development and testing easier.'))
->setArguments( ->setArguments(
array( array(
array( array(
'name' => 'target', 'name' => 'target',
'param' => 'id', 'param' => 'id',
'help' => pht( 'help' => pht('Build Target ID to attach the log to.'),
'Build Target ID to attach the log to.'),
), ),
)); ));
} }

View file

@ -31,6 +31,8 @@ final class HarbormasterBuildLogPHIDType extends PhabricatorPHIDType {
foreach ($handles as $phid => $handle) { foreach ($handles as $phid => $handle) {
$build_log = $objects[$phid]; $build_log = $objects[$phid];
$handle->setName(pht('Build Log %d', $build_log->getID()));
} }
} }

View file

@ -9,12 +9,13 @@ final class HarbormasterBuildLog
protected $logType; protected $logType;
protected $duration; protected $duration;
protected $live; protected $live;
protected $filePHID;
private $buildTarget = self::ATTACHABLE; private $buildTarget = self::ATTACHABLE;
private $rope; private $rope;
private $isOpen; private $isOpen;
const CHUNK_BYTE_LIMIT = 102400; const CHUNK_BYTE_LIMIT = 1048576;
public function __construct() { public function __construct() {
$this->rope = new PhutilRope(); $this->rope = new PhutilRope();
@ -60,18 +61,22 @@ final class HarbormasterBuildLog
->setLive(0) ->setLive(0)
->save(); ->save();
PhabricatorWorker::scheduleTask( $this->scheduleRebuild(false);
'HarbormasterLogWorker',
array(
'logPHID' => $this->getPHID(),
),
array(
'objectPHID' => $this->getPHID(),
));
return $this; return $this;
} }
public function scheduleRebuild($force) {
PhabricatorWorker::scheduleTask(
'HarbormasterLogWorker',
array(
'logPHID' => $this->getPHID(),
'force' => $force,
),
array(
'objectPHID' => $this->getPHID(),
));
}
protected function getConfiguration() { protected function getConfiguration() {
return array( return array(
@ -85,6 +90,7 @@ final class HarbormasterBuildLog
'duration' => 'uint32?', 'duration' => 'uint32?',
'live' => 'bool', 'live' => 'bool',
'filePHID' => 'phid?',
), ),
self::CONFIG_KEY_SCHEMA => array( self::CONFIG_KEY_SCHEMA => array(
'key_buildtarget' => array( 'key_buildtarget' => array(
@ -180,7 +186,7 @@ final class HarbormasterBuildLog
public function newChunkIterator() { public function newChunkIterator() {
return id(new HarbormasterBuildLogChunkIterator($this)) return id(new HarbormasterBuildLogChunkIterator($this))
->setPageSize(32); ->setPageSize(8);
} }
private function loadLastChunkInfo() { private function loadLastChunkInfo() {

View file

@ -5,6 +5,7 @@ final class HarbormasterBuildLogChunkIterator
private $log; private $log;
private $cursor; private $cursor;
private $asString;
private $min = 0; private $min = 0;
private $max = PHP_INT_MAX; private $max = PHP_INT_MAX;
@ -27,6 +28,11 @@ final class HarbormasterBuildLogChunkIterator
return $this; return $this;
} }
public function setAsString($as_string) {
$this->asString = $as_string;
return $this;
}
protected function loadPage() { protected function loadPage() {
if ($this->cursor > $this->max) { if ($this->cursor > $this->max) {
return array(); return array();
@ -43,7 +49,11 @@ final class HarbormasterBuildLogChunkIterator
$this->cursor = last($results)->getID() + 1; $this->cursor = last($results)->getID() + 1;
} }
return $results; if ($this->asString) {
return mpull($results, 'getChunkDisplayText');
} else {
return $results;
}
} }
} }

View file

@ -8,15 +8,6 @@ final class HarbormasterLogWorker extends HarbormasterWorker {
$data = $this->getTaskData(); $data = $this->getTaskData();
$log_phid = idx($data, 'logPHID'); $log_phid = idx($data, 'logPHID');
$log = id(new HarbormasterBuildLogQuery())
->setViewer($viewer)
->withPHIDs(array($log_phid))
->executeOne();
if (!$log) {
throw new PhabricatorWorkerPermanentFailureException(
pht('Invalid build log PHID "%s".', $log_phid));
}
$phid_key = PhabricatorHash::digestToLength($log_phid, 14); $phid_key = PhabricatorHash::digestToLength($log_phid, 14);
$lock_key = "build.log({$phid_key})"; $lock_key = "build.log({$phid_key})";
$lock = PhabricatorGlobalLock::newLock($lock_key); $lock = PhabricatorGlobalLock::newLock($lock_key);
@ -29,6 +20,25 @@ final class HarbormasterLogWorker extends HarbormasterWorker {
$caught = null; $caught = null;
try { try {
$log = id(new HarbormasterBuildLogQuery())
->setViewer($viewer)
->withPHIDs(array($log_phid))
->executeOne();
if (!$log) {
throw new PhabricatorWorkerPermanentFailureException(
pht(
'Invalid build log PHID "%s".',
$log_phid));
}
if ($log->getLive()) {
throw new PhabricatorWorkerPermanentFailureException(
pht(
'Log "%s" is still live. Logs can not be finalized until '.
'they have closed.',
$log_phid));
}
$this->finalizeBuildLog($log); $this->finalizeBuildLog($log);
} catch (Exception $ex) { } catch (Exception $ex) {
$caught = $ex; $caught = $ex;
@ -42,9 +52,51 @@ final class HarbormasterLogWorker extends HarbormasterWorker {
} }
private function finalizeBuildLog(HarbormasterBuildLog $log) { private function finalizeBuildLog(HarbormasterBuildLog $log) {
$viewer = $this->getViewer();
$data = $this->getTaskData();
$is_force = idx($data, 'force');
if ($log->canCompressLog()) { if ($log->canCompressLog()) {
$log->compressLog(); $log->compressLog();
} }
if ($is_force) {
$file_phid = $log->getFilePHID();
if ($file_phid) {
$file = id(new PhabricatorFileQuery())
->setViewer($viewer)
->withPHIDs(array($file_phid))
->executeOne();
if ($file) {
id(new PhabricatorDestructionEngine())
->destroyObject($file);
}
$log
->setFilePHID(null)
->save();
}
}
if (!$log->getFilePHID()) {
$iterator = $log->newChunkIterator()
->setAsString(true);
$source = id(new PhabricatorIteratorFileUploadSource())
->setName('harbormaster-log-'.$log->getID().'.log')
->setViewPolicy(PhabricatorPolicies::POLICY_NOONE)
->setMIMEType('application/octet-stream')
->setIterator($iterator);
$file = $source->uploadFile();
$file->attachToObject($log->getPHID());
$log
->setFilePHID($file->getPHID())
->save();
}
} }
} }