Page MenuHomePhabricator

D10394.diff
No OneTemporary

D10394.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
@@ -621,6 +621,8 @@
'DrydockManagementLeaseWorkflow' => 'applications/drydock/management/DrydockManagementLeaseWorkflow.php',
'DrydockManagementReleaseWorkflow' => 'applications/drydock/management/DrydockManagementReleaseWorkflow.php',
'DrydockManagementWorkflow' => 'applications/drydock/management/DrydockManagementWorkflow.php',
+ 'DrydockMinMaxBlueprintImplementation' => 'applications/drydock/blueprint/DrydockMinMaxBlueprintImplementation.php',
+ 'DrydockMinMaxExpiryBlueprintImplementation' => 'applications/drydock/blueprint/DrydockMinMaxExpiryBlueprintImplementation.php',
'DrydockMinMaxTestBlueprintImplementation' => 'applications/drydock/blueprint/DrydockMinMaxTestBlueprintImplementation.php',
'DrydockPreallocatedHostBlueprintImplementation' => 'applications/drydock/blueprint/DrydockPreallocatedHostBlueprintImplementation.php',
'DrydockQuery' => 'applications/drydock/query/DrydockQuery.php',
@@ -3384,7 +3386,9 @@
'DrydockManagementLeaseWorkflow' => 'DrydockManagementWorkflow',
'DrydockManagementReleaseWorkflow' => 'DrydockManagementWorkflow',
'DrydockManagementWorkflow' => 'PhabricatorManagementWorkflow',
- 'DrydockMinMaxTestBlueprintImplementation' => 'DrydockBlueprintImplementation',
+ 'DrydockMinMaxBlueprintImplementation' => 'DrydockBlueprintImplementation',
+ 'DrydockMinMaxExpiryBlueprintImplementation' => 'DrydockMinMaxBlueprintImplementation',
+ 'DrydockMinMaxTestBlueprintImplementation' => 'DrydockMinMaxExpiryBlueprintImplementation',
'DrydockPreallocatedHostBlueprintImplementation' => 'DrydockBlueprintImplementation',
'DrydockQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'DrydockResource' => array(
diff --git a/src/applications/drydock/blueprint/DrydockMinMaxTestBlueprintImplementation.php b/src/applications/drydock/blueprint/DrydockMinMaxBlueprintImplementation.php
copy from src/applications/drydock/blueprint/DrydockMinMaxTestBlueprintImplementation.php
copy to src/applications/drydock/blueprint/DrydockMinMaxBlueprintImplementation.php
--- a/src/applications/drydock/blueprint/DrydockMinMaxTestBlueprintImplementation.php
+++ b/src/applications/drydock/blueprint/DrydockMinMaxBlueprintImplementation.php
@@ -1,57 +1,13 @@
<?php
-final class DrydockMinMaxTestBlueprintImplementation
+abstract class DrydockMinMaxBlueprintImplementation
extends DrydockBlueprintImplementation {
- public function isEnabled() {
- return true;
- }
-
- public function isTest() {
- return true;
- }
-
- public function getBlueprintName() {
- return pht('Min / Max Count Test');
- }
-
- public function getDescription() {
- return pht('Used to test min / max counts.');
- }
-
public function canAllocateMoreResources(array $pool) {
$max_count = $this->getDetail('max-count');
return count($pool) < $max_count;
}
- protected function executeAllocateResource(
- DrydockResource $resource,
- DrydockLease $lease) {
-
- $path = '/srv/alloctest/'.$resource->getID();
-
- $resource
- ->setName($path)
- ->setStatus(DrydockResourceStatus::STATUS_PENDING)
- ->setAttributes(array(
- 'path' => $path))
- ->save();
-
- mkdir($path);
-
- sleep(10);
-
- $resource->setStatus(DrydockResourceStatus::STATUS_OPEN);
- $resource->save();
- }
-
- protected function canAllocateLease(
- DrydockResource $resource,
- DrydockLease $lease) {
-
- return true;
- }
-
protected function shouldAllocateLease(
DrydockAllocationContext $context,
DrydockResource $resource,
@@ -87,45 +43,6 @@
return $minimum_lease_resource_id === $resource->getID();
}
- protected function executeAcquireLease(
- DrydockResource $resource,
- DrydockLease $lease) {
-
- while ($resource->getStatus() == DrydockResourceStatus::STATUS_PENDING) {
- // This resource is still being set up by another allocator, wait until
- // it is set to open.
- sleep(5);
- $resource->reload();
- }
-
- $path = $resource->getAttribute('path').'/'.$lease->getID();
-
- mkdir($path);
-
- sleep(10);
-
- $lease->setAttribute('path', $path);
- }
-
- public function getType() {
- return 'storage';
- }
-
- public function getInterface(
- DrydockResource $resource,
- DrydockLease $lease,
- $type) {
-
- throw new Exception("No interface of type '{$type}'.");
- }
-
- protected function executeReleaseLease(
- DrydockResource $resource,
- DrydockLease $lease) {
-
- execx('rm -R %s', $lease->getAttribute('path'));
- }
-
protected function shouldCloseUnleasedResource(
DrydockAllocationContext $context,
DrydockResource $resource) {
@@ -134,20 +51,19 @@
$this->getDetail('min-count');
}
- protected function executeCloseResource(DrydockResource $resource) {
- execx('rm -R %s', $resource->getAttribute('path'));
- }
-
-
public function getFieldSpecifications() {
return array(
+ 'min-max-header' => array(
+ 'name' => pht('Allocation Limits'),
+ 'type' => 'header',
+ ),
'min-count' => array(
'name' => pht('Minimum Resources'),
'type' => 'int',
'required' => true,
'caption' => pht(
'The minimum number of resources to keep open in '.
- 'this pool at all times.')
+ 'this pool at all times.'),
),
'max-count' => array(
'name' => pht('Maximum Resources'),
@@ -159,7 +75,7 @@
'leases on existing resources and thus exceeding '.
'`leases-per-resource`. If this parameter is left blank, then '.
'this blueprint has no limit on the number of resources it '.
- 'can allocate.')
+ 'can allocate.'),
),
'leases-per-resource' => array(
'name' => pht('Maximum Leases Per Resource'),
@@ -174,7 +90,7 @@
'another resource providing `max-count` would not be exceeded.'.
' If `max-count` would be exceeded, Drydock will instead '.
'overallocate the lease to an existing resource and '.
- 'exceed the limit specified here.')
+ 'exceed the limit specified here.'),
),
);
}
diff --git a/src/applications/drydock/blueprint/DrydockMinMaxExpiryBlueprintImplementation.php b/src/applications/drydock/blueprint/DrydockMinMaxExpiryBlueprintImplementation.php
new file mode 100644
--- /dev/null
+++ b/src/applications/drydock/blueprint/DrydockMinMaxExpiryBlueprintImplementation.php
@@ -0,0 +1,92 @@
+<?php
+
+abstract class DrydockMinMaxExpiryBlueprintImplementation
+ extends DrydockMinMaxBlueprintImplementation {
+
+ public function canAllocateMoreResources(array $pool) {
+ $max_count = $this->getDetail('max-count');
+
+ $expiry = $this->getDetail('expiry');
+
+ // Only count resources that haven't yet expired, so we can overallocate
+ // if another expired resource is about to be closed (but is still waiting
+ // on it's current resources to be released).
+ $count = 0;
+ $now = time();
+ foreach ($pool as $resource) {
+ $lifetime = $now - $resource->getDateCreated();
+ if ($lifetime <= $expiry) {
+ $count++;
+ }
+ }
+
+ return $count < $max_count;
+ }
+
+ protected function shouldAllocateLease(
+ DrydockAllocationContext $context,
+ DrydockResource $resource,
+ DrydockLease $lease) {
+
+ // If we have no leases allocated to this resource, then we always allow
+ // the parent logic to evaluate. The reason for this is that an expired
+ // resource can only be closed when a lease is released, so if the resource
+ // is open and has no leases, then we'll never reach the code that checks
+ // the expiry to close it. So we allow this lease to occur, so that we'll
+ // hit `shouldCloseUnleasedResource` in the future and the resource will
+ // be closed.
+ if ($context->getCurrentResourceLeaseCount() === 0) {
+ return parent::shouldAllocateLease($context, $resource, $lease);
+ }
+
+ $expiry = $this->getDetail('expiry');
+
+ if ($expiry !== null) {
+ $lifetime = time() - $resource->getDateCreated();
+
+ if ($lifetime > $expiry) {
+ // Prevent allocation of leases to this resource, since it's over
+ // it's lifetime allowed.
+ return false;
+ }
+ }
+
+ return parent::shouldAllocateLease($context, $resource, $lease);
+ }
+
+ protected function shouldCloseUnleasedResource(
+ DrydockAllocationContext $context,
+ DrydockResource $resource) {
+
+ $expiry = $this->getDetail('expiry');
+
+ if ($expiry !== null) {
+ $lifetime = time() - $resource->getDateCreated();
+
+ if ($lifetime > $expiry) {
+ // Force closure of resources that have expired.
+ return true;
+ }
+ }
+
+ return parent::shouldCloseUnleasedResource($context, $resource);
+ }
+
+ public function getFieldSpecifications() {
+ return array(
+ 'expiry-header' => array(
+ 'name' => pht('Resource Expiration'),
+ 'type' => 'header',
+ ),
+ 'expiry' => array(
+ 'name' => pht('Expiry Time'),
+ 'type' => 'int',
+ 'caption' => pht(
+ 'After this time (in seconds) has elapsed since resource creation, '.
+ 'Drydock will no longer lease against the resource, and it will be '.
+ 'closed when there are no more leases (regardless of minimum '.
+ 'resource limits).'),
+ ),
+ ) + parent::getFieldSpecifications();
+ }
+}
diff --git a/src/applications/drydock/blueprint/DrydockMinMaxTestBlueprintImplementation.php b/src/applications/drydock/blueprint/DrydockMinMaxTestBlueprintImplementation.php
--- a/src/applications/drydock/blueprint/DrydockMinMaxTestBlueprintImplementation.php
+++ b/src/applications/drydock/blueprint/DrydockMinMaxTestBlueprintImplementation.php
@@ -1,7 +1,7 @@
<?php
final class DrydockMinMaxTestBlueprintImplementation
- extends DrydockBlueprintImplementation {
+ extends DrydockMinMaxExpiryBlueprintImplementation {
public function isEnabled() {
return true;
@@ -19,11 +19,6 @@
return pht('Used to test min / max counts.');
}
- public function canAllocateMoreResources(array $pool) {
- $max_count = $this->getDetail('max-count');
- return count($pool) < $max_count;
- }
-
protected function executeAllocateResource(
DrydockResource $resource,
DrydockLease $lease) {
@@ -39,7 +34,7 @@
mkdir($path);
- sleep(10);
+ sleep($this->getDetail('seconds-to-open'));
$resource->setStatus(DrydockResourceStatus::STATUS_OPEN);
$resource->save();
@@ -52,41 +47,6 @@
return true;
}
- protected function shouldAllocateLease(
- DrydockAllocationContext $context,
- DrydockResource $resource,
- DrydockLease $lease) {
-
- // If the current resource can allocate a lease, allow it.
- if ($context->getCurrentResourceLeaseCount() <
- $this->getDetail('leases-per-resource')) {
- return true;
- }
-
- // We don't have enough room under the `leases-per-instance` limit, but
- // this limit can be bypassed if we've allocated all of the resources
- // we allow.
- $open_count = $context->getBlueprintOpenResourceCount();
- if ($open_count < $this->getDetail('max-count')) {
- return false;
- }
-
- // Find the resource that has the least leases.
- $all_lease_counts_grouped = $context->getResourceLeaseCounts();
- $minimum_lease_count = $all_lease_counts_grouped[$resource->getID()];
- $minimum_lease_resource_id = $resource->getID();
- foreach ($all_lease_counts_grouped as $resource_id => $lease_count) {
- if ($minimum_lease_count > $lease_count) {
- $minimum_lease_count = $lease_count;
- $minimum_lease_resource_id = $resource_id;
- }
- }
-
- // If we are that resource, then allow it, otherwise let the other
- // less-leased resource run through this logic and allocate the lease.
- return $minimum_lease_resource_id === $resource->getID();
- }
-
protected function executeAcquireLease(
DrydockResource $resource,
DrydockLease $lease) {
@@ -102,7 +62,7 @@
mkdir($path);
- sleep(10);
+ sleep($this->getDetail('seconds-to-lease'));
$lease->setAttribute('path', $path);
}
@@ -138,44 +98,26 @@
execx('rm -R %s', $resource->getAttribute('path'));
}
-
public function getFieldSpecifications() {
return array(
- 'min-count' => array(
- 'name' => pht('Minimum Resources'),
- 'type' => 'int',
- 'required' => true,
- 'caption' => pht(
- 'The minimum number of resources to keep open in '.
- 'this pool at all times.')
+ 'test-configuration' => array(
+ 'name' => pht('Test Configuration'),
+ 'type' => 'header',
),
- 'max-count' => array(
- 'name' => pht('Maximum Resources'),
+ 'seconds-to-open' => array(
+ 'name' => pht('Seconds to Open'),
'type' => 'int',
'caption' => pht(
- 'The maximum number of resources to allow open at any time. '.
- 'If the number of resources currently open are equal to '.
- '`max-count` and another lease is requested, Drydock will place '.
- 'leases on existing resources and thus exceeding '.
- '`leases-per-resource`. If this parameter is left blank, then '.
- 'this blueprint has no limit on the number of resources it '.
- 'can allocate.')
+ 'The time to sleep during creation of a resource.'),
+ 'required' => true,
),
- 'leases-per-resource' => array(
- 'name' => pht('Maximum Leases Per Resource'),
+ 'seconds-to-lease' => array(
+ 'name' => pht('Seconds to Lease'),
'type' => 'int',
- 'required' => true,
'caption' => pht(
- 'The soft limit on the number of leases to allocate to an '.
- 'individual resource in the pool. Drydock will choose the '.
- 'resource with the lowest number of leases when selecting a '.
- 'resource to lease on. If all current resources have '.
- '`leases-per-resource` leases on them, then Drydock will allocate '.
- 'another resource providing `max-count` would not be exceeded.'.
- ' If `max-count` would be exceeded, Drydock will instead '.
- 'overallocate the lease to an existing resource and '.
- 'exceed the limit specified here.')
+ 'The time to sleep while acquiring a lease.'),
+ 'required' => true,
),
- );
+ ) + parent::getFieldSpecifications();
}
}
diff --git a/src/applications/drydock/util/DrydockAllocationContext.php b/src/applications/drydock/util/DrydockAllocationContext.php
--- a/src/applications/drydock/util/DrydockAllocationContext.php
+++ b/src/applications/drydock/util/DrydockAllocationContext.php
@@ -41,7 +41,8 @@
' ON lease.resourceID = resource.id '.
'WHERE resource.blueprintPHID = %s '.
'AND resource.status IN (%Ld) '.
- 'AND lease.status IN (%Ld) ',
+ 'AND lease.status IN (%Ld) '.
+ 'GROUP BY resource.id',
$table_resource,
$table_lease,
$blueprint->getPHID(),

File Metadata

Mime Type
text/plain
Expires
Mon, Mar 17, 4:09 PM (1 w, 3 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7460065
Default Alt Text
D10394.diff (15 KB)

Event Timeline