Page MenuHomePhabricator

D14161.id.diff
No OneTemporary

D14161.id.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1002,7 +1002,9 @@
'HarbormasterController' => 'applications/harbormaster/controller/HarbormasterController.php',
'HarbormasterCreateArtifactConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterCreateArtifactConduitAPIMethod.php',
'HarbormasterDAO' => 'applications/harbormaster/storage/HarbormasterDAO.php',
+ 'HarbormasterDrydockCommandBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterDrydockCommandBuildStepImplementation.php',
'HarbormasterDrydockLeaseArtifact' => 'applications/harbormaster/artifact/HarbormasterDrydockLeaseArtifact.php',
+ 'HarbormasterExecFuture' => 'applications/harbormaster/future/HarbormasterExecFuture.php',
'HarbormasterExternalBuildStepGroup' => 'applications/harbormaster/stepgroup/HarbormasterExternalBuildStepGroup.php',
'HarbormasterFileArtifact' => 'applications/harbormaster/artifact/HarbormasterFileArtifact.php',
'HarbormasterHTTPRequestBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterHTTPRequestBuildStepImplementation.php',
@@ -4789,7 +4791,9 @@
'HarbormasterController' => 'PhabricatorController',
'HarbormasterCreateArtifactConduitAPIMethod' => 'HarbormasterConduitAPIMethod',
'HarbormasterDAO' => 'PhabricatorLiskDAO',
+ 'HarbormasterDrydockCommandBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
'HarbormasterDrydockLeaseArtifact' => 'HarbormasterArtifact',
+ 'HarbormasterExecFuture' => 'Future',
'HarbormasterExternalBuildStepGroup' => 'HarbormasterBuildStepGroup',
'HarbormasterFileArtifact' => 'HarbormasterArtifact',
'HarbormasterHTTPRequestBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
diff --git a/src/applications/harbormaster/future/HarbormasterExecFuture.php b/src/applications/harbormaster/future/HarbormasterExecFuture.php
new file mode 100644
--- /dev/null
+++ b/src/applications/harbormaster/future/HarbormasterExecFuture.php
@@ -0,0 +1,50 @@
+<?php
+
+final class HarbormasterExecFuture
+ extends Future {
+
+ private $future;
+ private $stdout;
+ private $stderr;
+
+ public function setFuture(ExecFuture $future) {
+ $this->future = $future;
+ return $this;
+ }
+
+ public function getFuture() {
+ return $this->future;
+ }
+
+ public function setLogs(
+ HarbormasterBuildLog $stdout,
+ HarbormasterBuildLog $stderr) {
+ $this->stdout = $stdout;
+ $this->stderr = $stderr;
+ return $this;
+ }
+
+ public function isReady() {
+ $future = $this->getFuture();
+
+ $result = $future->isReady();
+
+ list($stdout, $stderr) = $future->read();
+ $future->discardBuffers();
+
+ if ($this->stdout) {
+ $this->stdout->append($stdout);
+ }
+
+ if ($this->stderr) {
+ $this->stderr->append($stderr);
+ }
+
+ return $result;
+ }
+
+ protected function getResult() {
+ return $this->getFuture()->getResult();
+ }
+
+}
diff --git a/src/applications/harbormaster/step/HarbormasterBuildStepImplementation.php b/src/applications/harbormaster/step/HarbormasterBuildStepImplementation.php
--- a/src/applications/harbormaster/step/HarbormasterBuildStepImplementation.php
+++ b/src/applications/harbormaster/step/HarbormasterBuildStepImplementation.php
@@ -238,22 +238,21 @@
return $build->getBuildGeneration() !== $target->getBuildGeneration();
}
- protected function resolveFuture(
+ protected function resolveFutures(
HarbormasterBuild $build,
HarbormasterBuildTarget $target,
- Future $future) {
+ array $futures) {
- $futures = new FutureIterator(array($future));
+ $futures = new FutureIterator($futures);
foreach ($futures->setUpdateInterval(5) as $key => $future) {
if ($future === null) {
$build->reload();
if ($this->shouldAbort($build, $target)) {
throw new HarbormasterBuildAbortedException();
}
- } else {
- return $future->resolve();
}
}
+
}
diff --git a/src/applications/harbormaster/step/HarbormasterDrydockCommandBuildStepImplementation.php b/src/applications/harbormaster/step/HarbormasterDrydockCommandBuildStepImplementation.php
new file mode 100644
--- /dev/null
+++ b/src/applications/harbormaster/step/HarbormasterDrydockCommandBuildStepImplementation.php
@@ -0,0 +1,90 @@
+<?php
+
+final class HarbormasterDrydockCommandBuildStepImplementation
+ extends HarbormasterBuildStepImplementation {
+
+ public function getName() {
+ return pht('Drydock: Run Command');
+ }
+
+ public function getGenericDescription() {
+ return pht('Run a command on Drydock resource.');
+ }
+
+ public function getBuildStepGroupKey() {
+ return HarbormasterPrototypeBuildStepGroup::GROUPKEY;
+ }
+
+ public function getDescription() {
+ return pht(
+ 'Run command %s on %s.',
+ $this->formatSettingForDescription('command'),
+ $this->formatSettingForDescription('artifact'));
+ }
+
+ public function execute(
+ HarbormasterBuild $build,
+ HarbormasterBuildTarget $build_target) {
+ $viewer = PhabricatorUser::getOmnipotentUser();
+
+ $settings = $this->getSettings();
+ $variables = $build_target->getVariables();
+
+ $artifact = $build_target->loadArtifact($settings['artifact']);
+ $impl = $artifact->getArtifactImplementation();
+ $lease = $impl->loadArtifactLease($viewer);
+
+ // TODO: Require active lease.
+
+ $command = $this->mergeVariables(
+ 'vcsprintf',
+ $settings['command'],
+ $variables);
+
+ $interface = $lease->getInterface(DrydockCommandInterface::INTERFACE_TYPE);
+
+ $exec_future = $interface->getExecFuture('%C', $command);
+
+ $harbor_future = id(new HarbormasterExecFuture())
+ ->setFuture($exec_future)
+ ->setLogs(
+ $build_target->newLog('remote', 'stdout'),
+ $build_target->newLog('remote', 'stderr'));
+
+ $this->resolveFutures(
+ $build,
+ $build_target,
+ array($harbor_future));
+
+ list($err) = $harbor_future->resolve();
+ if ($err) {
+ throw new HarbormasterBuildFailureException();
+ }
+ }
+
+ public function getArtifactInputs() {
+ return array(
+ array(
+ 'name' => pht('Drydock Lease'),
+ 'key' => $this->getSetting('artifact'),
+ 'type' => HarbormasterWorkingCopyArtifact::ARTIFACTCONST,
+ ),
+ );
+ }
+
+ public function getFieldSpecifications() {
+ return array(
+ 'command' => array(
+ 'name' => pht('Command'),
+ 'type' => 'text',
+ 'required' => true,
+ ),
+ 'artifact' => array(
+ 'name' => pht('Drydock Lease'),
+ 'type' => 'text',
+ 'required' => true,
+ ),
+ );
+ }
+
+}
diff --git a/src/applications/harbormaster/step/HarbormasterHTTPRequestBuildStepImplementation.php b/src/applications/harbormaster/step/HarbormasterHTTPRequestBuildStepImplementation.php
--- a/src/applications/harbormaster/step/HarbormasterHTTPRequestBuildStepImplementation.php
+++ b/src/applications/harbormaster/step/HarbormasterHTTPRequestBuildStepImplementation.php
@@ -51,9 +51,6 @@
$settings['uri'],
$variables);
- $log_body = $build->createLog($build_target, $uri, 'http-body');
- $start = $log_body->start();
-
$method = nonempty(idx($settings, 'method'), 'POST');
$future = id(new HTTPSFuture($uri))
@@ -70,16 +67,30 @@
$key->getPasswordEnvelope());
}
- list($status, $body, $headers) = $this->resolveFuture(
+ $this->resolveFutures(
$build,
$build_target,
- $future);
+ array($future));
+
+ list($status, $body, $headers) = $future->resolve();
+
+ $header_lines = array();
+ foreach ($headers as $header) {
+ list($head, $tail) = $header;
+ $header_lines[] = "{$head}: {$tail}";
+ }
+ $header_lines = implode("\n", $header_lines);
+
+ $build_target
+ ->newLog($uri, 'http.head')
+ ->append($header_lines);
- $log_body->append($body);
- $log_body->finalize($start);
+ $build_target
+ ->newLog($uri, 'http.body')
+ ->append($body);
if ($status->getStatusCode() != 200) {
- $build->setBuildStatus(HarbormasterBuild::STATUS_FAILED);
+ throw new HarbormasterBuildFailureException();
}
}
diff --git a/src/applications/harbormaster/step/HarbormasterLeaseWorkingCopyBuildStepImplementation.php b/src/applications/harbormaster/step/HarbormasterLeaseWorkingCopyBuildStepImplementation.php
--- a/src/applications/harbormaster/step/HarbormasterLeaseWorkingCopyBuildStepImplementation.php
+++ b/src/applications/harbormaster/step/HarbormasterLeaseWorkingCopyBuildStepImplementation.php
@@ -88,7 +88,7 @@
array(
'name' => pht('Working Copy'),
'key' => $this->getSetting('name'),
- 'type' => HarbormasterHostArtifact::ARTIFACTCONST,
+ 'type' => HarbormasterWorkingCopyArtifact::ARTIFACTCONST,
),
);
}
diff --git a/src/applications/harbormaster/storage/build/HarbormasterBuildLog.php b/src/applications/harbormaster/storage/build/HarbormasterBuildLog.php
--- a/src/applications/harbormaster/storage/build/HarbormasterBuildLog.php
+++ b/src/applications/harbormaster/storage/build/HarbormasterBuildLog.php
@@ -10,6 +10,7 @@
protected $live;
private $buildTarget = self::ATTACHABLE;
+ private $start;
const CHUNK_BYTE_LIMIT = 102400;
@@ -18,6 +19,12 @@
*/
const ENCODING_TEXT = 'text';
+ public function __destruct() {
+ if ($this->live) {
+ $this->finalize($this->start);
+ }
+ }
+
public static function initializeNewBuildLog(
HarbormasterBuildTarget $build_target) {
@@ -75,6 +82,8 @@
$this->setLive(1);
$this->save();
+ $this->start = PhabricatorTime::getNow();
+
return time();
}
diff --git a/src/applications/harbormaster/storage/build/HarbormasterBuildTarget.php b/src/applications/harbormaster/storage/build/HarbormasterBuildTarget.php
--- a/src/applications/harbormaster/storage/build/HarbormasterBuildTarget.php
+++ b/src/applications/harbormaster/storage/build/HarbormasterBuildTarget.php
@@ -249,6 +249,20 @@
return $artifact;
}
+ public function newLog($log_source, $log_type) {
+ $log_source = id(new PhutilUTF8StringTruncator())
+ ->setMaximumBytes(250)
+ ->truncateString($log_source);
+
+ $log = HarbormasterBuildLog::initializeNewBuildLog($this)
+ ->setLogSource($log_source)
+ ->setLogType($log_type);
+
+ $log->start();
+
+ return $log;
+ }
+
/* -( Status )------------------------------------------------------------- */

File Metadata

Mime Type
text/plain
Expires
Sun, Nov 10, 4:21 AM (1 w, 2 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6748511
Default Alt Text
D14161.id.diff (10 KB)

Event Timeline