Page MenuHomePhabricator

D13507.diff
No OneTemporary

D13507.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
@@ -869,6 +869,7 @@
'DrydockWebrootInterface' => 'applications/drydock/interface/webroot/DrydockWebrootInterface.php',
'DrydockWinRMCommandInterface' => 'applications/drydock/interface/command/DrydockWinRMCommandInterface.php',
'DrydockWorkingCopyBlueprintImplementation' => 'applications/drydock/blueprint/DrydockWorkingCopyBlueprintImplementation.php',
+ 'DrydockWorkingCopyCacheBlueprintImplementation' => 'applications/drydock/blueprint/DrydockWorkingCopyCacheBlueprintImplementation.php',
'FeedConduitAPIMethod' => 'applications/feed/conduit/FeedConduitAPIMethod.php',
'FeedPublishConduitAPIMethod' => 'applications/feed/conduit/FeedPublishConduitAPIMethod.php',
'FeedPublisherHTTPWorker' => 'applications/feed/worker/FeedPublisherHTTPWorker.php',
@@ -4577,6 +4578,7 @@
'DrydockWebrootInterface' => 'DrydockInterface',
'DrydockWinRMCommandInterface' => 'DrydockCommandInterface',
'DrydockWorkingCopyBlueprintImplementation' => 'DrydockBlueprintImplementation',
+ 'DrydockWorkingCopyCacheBlueprintImplementation' => 'DrydockBlueprintImplementation',
'FeedConduitAPIMethod' => 'ConduitAPIMethod',
'FeedPublishConduitAPIMethod' => 'FeedConduitAPIMethod',
'FeedPublisherHTTPWorker' => 'FeedPushWorker',
diff --git a/src/applications/drydock/blueprint/DrydockPreallocatedHostBlueprintImplementation.php b/src/applications/drydock/blueprint/DrydockPreallocatedHostBlueprintImplementation.php
--- a/src/applications/drydock/blueprint/DrydockPreallocatedHostBlueprintImplementation.php
+++ b/src/applications/drydock/blueprint/DrydockPreallocatedHostBlueprintImplementation.php
@@ -35,7 +35,9 @@
DrydockResource $resource,
DrydockLease $lease) {
return
- $lease->getAttribute('platform') === $resource->getAttribute('platform');
+ $lease->getAttribute('platform') ===
+ $resource->getAttribute('platform') ||
+ $lease->getAttribute('platform') === null;
}
protected function shouldAllocateLease(
@@ -87,6 +89,10 @@
$cmd->execx('mkdir %s', $full_path);
$lease->setAttribute('path', $full_path);
+ if ($lease->getAttribute('platform') === null) {
+ // If the lease does not have a platform set, set it now.
+ $lease->setAttribute('platform', $v_platform);
+ }
}
public function getType() {
diff --git a/src/applications/drydock/blueprint/DrydockWorkingCopyCacheBlueprintImplementation.php b/src/applications/drydock/blueprint/DrydockWorkingCopyCacheBlueprintImplementation.php
new file mode 100644
--- /dev/null
+++ b/src/applications/drydock/blueprint/DrydockWorkingCopyCacheBlueprintImplementation.php
@@ -0,0 +1,258 @@
+<?php
+
+final class DrydockWorkingCopyCacheBlueprintImplementation
+ extends DrydockBlueprintImplementation {
+
+ public function isEnabled() {
+ return true;
+ }
+
+ public function getBlueprintName() {
+ return pht('Working Copy Cache');
+ }
+
+ public function getDescription() {
+ return pht('Allows Drydock to cache repositories on host resources.');
+ }
+
+ public function canAllocateResourceForLease(DrydockLease $lease) {
+ return true;
+ }
+
+ protected function canAllocateLease(
+ DrydockResource $resource,
+ DrydockLease $lease) {
+
+ $resource_match = $lease->getAttribute('host.resource') ===
+ $resource->getAttribute('host.resource');
+ $url_match = $lease->getAttribute('url') ===
+ $resource->getAttribute('url');
+
+ $can_allocate = $resource_match && $url_match;
+
+ if ($can_allocate) {
+ $this->log(pht(
+ 'This blueprint can allocate a resource for the specified lease.'));
+ } else {
+ $this->log(pht(
+ 'This blueprint can not allocate a resource for the specified lease.'));
+ }
+
+ return $can_allocate;
+ }
+
+ protected function shouldAllocateLease(
+ DrydockAllocationContext $context,
+ DrydockResource $resource,
+ DrydockLease $lease) {
+
+ return true;
+ }
+
+ protected function executeInitializePendingResource(
+ DrydockResource $resource,
+ DrydockLease $lease) {
+
+ $url = $lease->getAttribute('url');
+ $host_resource_id = $lease->getAttribute('host.resource');
+
+ $resource
+ ->setAttribute('url', $url)
+ ->setAttribute('host.resource', $host_resource_id)
+ ->save();
+ }
+
+ protected function executeAllocateResource(
+ DrydockResource $resource,
+ DrydockLease $lease) {
+
+ $url = $lease->getAttribute('url');
+ $host_resource_id = $lease->getAttribute('host.resource');
+
+ $resource
+ ->setName(pht(
+ 'Working Copy Cache (%s on host resource %d)',
+ $url,
+ $host_resource_id))
+ ->setStatus(DrydockResourceStatus::STATUS_PENDING)
+ ->save();
+
+ $host_lease = id(new DrydockLease())
+ ->setResourceType('host')
+ ->setAttributes(
+ array(
+ 'resourceID' => $host_resource_id,
+ ))
+ ->queueForActivation();
+ $this->log(pht(
+ 'Acquiring new host lease %d for working copy cache (on resource %d)...',
+ $host_lease->getID(),
+ $host_resource_id));
+ $host_lease->waitUntilActive();
+ $this->log(pht(
+ 'Lease %d acquired for working copy resource.',
+ $host_lease->getID()));
+
+ $resource
+ ->setAttribute('host.lease', $host_lease->getID())
+ ->save();
+
+ $this->log(pht(
+ 'Cloning repository at "%s" to "%s"...',
+ $url,
+ $host_lease->getAttribute('path')));
+
+ $cmd = $this->getCommandInterfaceForLease($host_lease);
+ $cmd->execx(
+ 'git clone --bare %s .',
+ $url);
+
+ $this->log('Cloned repository cache.');
+
+ $resource
+ ->setStatus(DrydockResourceStatus::STATUS_OPEN)
+ ->save();
+ return $resource;
+ }
+
+ protected function executeAcquireLease(
+ DrydockResource $resource,
+ DrydockLease $lease) {
+
+ $this->log(pht(
+ 'Starting acquisition of lease from resource %d',
+ $resource->getID()));
+
+ while ($resource->getStatus() == DrydockResourceStatus::STATUS_PENDING) {
+ $this->log(pht(
+ 'Resource %d is still pending, waiting until it is in an open status',
+ $resource->getID()));
+
+ // This resource is still being set up by another allocator, wait until
+ // it is set to open.
+ sleep(5);
+ $resource->reload();
+ }
+
+ $host_lease = id(new DrydockLeaseQuery())
+ ->setViewer(PhabricatorUser::getOmnipotentUser())
+ ->withIDs(array($resource->getAttribute('host.lease')))
+ ->executeOne();
+ if ($host_lease === null) {
+ throw new Exception(pht(
+ 'No resource found with ID %d',
+ $resource->getAttribute('host.lease')));
+ }
+
+ // Ensure the host lease and resource are still active and open.
+ if ($host_lease->getStatus() != DrydockLeaseStatus::STATUS_ACTIVE ||
+ $host_lease->getResource()->getStatus() !=
+ DrydockResourceStatus::STATUS_OPEN) {
+
+ // Our host lease has been released or our host resource has been
+ // closed. No further leases against this working copy cache
+ // resource will succeed, so force ourselves into the closed
+ // status and fail this lease.
+ $resource
+ ->setStatus(DrydockResourceStatus::STATUS_DESTROYED)
+ ->save();
+ throw new Exception(pht(
+ 'The host lease or resource for this working copy '.
+ 'cache was released or closed. Lease was in status "%s", '.
+ 'resource was in status "%s". Automatically '.
+ 'marking this working copy resource as destroyed.',
+ DrydockLeaseStatus::getNameForStatus($host_lease->getStatus()),
+ DrydockResourceStatus::getNameForStatus(
+ $host_lease->getResource()->getStatus())));
+ }
+
+ // We must lock the resource while we perform the cache update,
+ // because otherwise we'll end up running multiple read-write
+ // VCS operations in the same directory at the same time.
+ $lock = PhabricatorGlobalLock::newLock(
+ 'drydock-working-copy-cache-update-'.$host_lease->getID());
+ $lock->lock(1000000);
+ try {
+ $cmd = $this->getCommandInterfaceForLease($host_lease);
+
+ $this->log(pht(
+ 'Fetching latest commits for repository at "%s"',
+ $host_lease->getAttribute('path')));
+ $cmd->exec('git fetch origin +refs/heads/*:refs/heads/*');
+ $cmd->exec(
+ 'git fetch origin +refs/tags/phabricator/diff/*:'.
+ 'refs/tags/phabricator/diff/*');
+ $this->log(pht('Fetched latest commits.'));
+
+ $lock->unlock();
+ } catch (Exception $ex) {
+ $lock->unlock();
+ throw $ex;
+ }
+
+ // We don't need to perform any cloning or initialization here, the leases
+ // just count how many users of the working copy cache there are.
+
+ $lease->setAttribute('path', $host_lease->getAttribute('path'));
+ }
+
+ private function getCommandInterfaceForLease(DrydockLease $lease) {
+ if ($lease->getAttribute('platform') === 'windows') {
+ return $lease->getInterface(
+ 'command-'.PhutilCommandString::MODE_WINDOWSCMD);
+ } else {
+ return $lease->getInterface(
+ 'command-'.PhutilCommandString::MODE_BASH);
+ }
+ }
+
+ public function getType() {
+ return 'working-copy-cache';
+ }
+
+ public function getInterface(
+ DrydockResource $resource,
+ DrydockLease $lease,
+ $type) {
+
+ throw new Exception(pht("No interface of type '%s'.", $type));
+ }
+
+ protected function executeReleaseLease(
+ DrydockResource $resource,
+ DrydockLease $lease) {
+
+ // No release logic require for leases.
+ }
+
+ protected function shouldCloseUnleasedResource(
+ DrydockAllocationContext $context,
+ DrydockResource $resource) {
+
+ return false;
+ }
+
+ protected function executeCloseResource(DrydockResource $resource) {
+ $this->log(pht(
+ 'Releasing resource host lease %d',
+ $resource->getAttribute('host.lease')));
+ try {
+ $host_lease = $this->loadLease($resource->getAttribute('host.lease'));
+
+ $host_resource = $host_lease->getResource();
+ $host_blueprint = $host_resource->getBlueprint();
+ $host_blueprint->releaseLease($host_resource, $host_lease);
+
+ $this->log(pht(
+ 'Released resource host lease %d',
+ $resource->getAttribute('host.lease')));
+ } catch (Exception $ex) {
+ $this->log(pht(
+ 'Unable to release resource host lease %d: "%s"',
+ $resource->getAttribute('host.lease'),
+ (string)$ex));
+ }
+ }
+
+
+}

File Metadata

Mime Type
text/plain
Expires
Nov 6 2025, 3:22 AM (9 w, 3 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
8796021
Default Alt Text
D13507.diff (10 KB)

Event Timeline