mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-22 14:52:41 +01:00
More Drydock Stuff
Summary: - Still really really rough. - Adds a full synchronous mode for debugging. - Adds some logging. - It can now allocate EC2 machines and put webroots on them in a hacky, terrible way. - Adds a base query class. Test Plan: oh hey look a test page? http://ec2-50-18-65-151.us-west-1.compute.amazonaws.com:2011/ Reviewers: btrahan Reviewed By: btrahan CC: aran, epriestley Maniphest Tasks: T1049 Differential Revision: https://secure.phabricator.com/D2026
This commit is contained in:
parent
bf2422afc8
commit
914f044b62
36 changed files with 905 additions and 68 deletions
10
resources/sql/patches/121.drydocklog.sql
Normal file
10
resources/sql/patches/121.drydocklog.sql
Normal file
|
@ -0,0 +1,10 @@
|
|||
CREATE TABLE phabricator_drydock.drydock_log (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
resourceID INT UNSIGNED,
|
||||
leaseID INT UNSIGNED,
|
||||
epoch INT UNSIGNED NOT NULL,
|
||||
message LONGTEXT COLLATE utf8_general_ci NOT NULL,
|
||||
KEY (resourceID, epoch),
|
||||
KEY (leaseID, epoch),
|
||||
KEY (epoch)
|
||||
) ENGINE=InnoDB, COLLATE utf8_general_ci;
|
|
@ -26,11 +26,20 @@ phutil_require_module('phutil', 'future/exec');
|
|||
PhutilServiceProfiler::installEchoListener();
|
||||
|
||||
$allocator = new DrydockAllocator();
|
||||
$allocator->setResourceType('host');
|
||||
$allocator->makeSynchronous();
|
||||
$allocator->setResourceType('webroot');
|
||||
$lease = $allocator->allocate();
|
||||
|
||||
$lease->waitUntilActive();
|
||||
|
||||
|
||||
$cmd = $lease->getInterface('webroot');
|
||||
echo "URI: ".$cmd->getURI()."\n";
|
||||
|
||||
$lease->release();
|
||||
|
||||
die("Done.\n");
|
||||
|
||||
$i_file = $lease->getInterface('command');
|
||||
|
||||
list($stdout) = $i_file->execx('ls / ; echo -- ; uptime ; echo -- ; uname -n');
|
||||
|
|
|
@ -354,6 +354,8 @@ phutil_register_library_map(array(
|
|||
'DiffusionView' => 'applications/diffusion/view/base',
|
||||
'DrydockAllocator' => 'applications/drydock/allocator/resource',
|
||||
'DrydockAllocatorWorker' => 'applications/drydock/allocator/worker',
|
||||
'DrydockApacheWebrootBlueprint' => 'applications/drydock/blueprint/webroot/apache',
|
||||
'DrydockApacheWebrootInterface' => 'applications/drydock/interface/webroot/apache',
|
||||
'DrydockBlueprint' => 'applications/drydock/blueprint/base',
|
||||
'DrydockCommandInterface' => 'applications/drydock/interface/command/base',
|
||||
'DrydockConstants' => 'applications/drydock/constants/base',
|
||||
|
@ -366,12 +368,17 @@ phutil_register_library_map(array(
|
|||
'DrydockLeaseStatus' => 'applications/drydock/constants/leasestatus',
|
||||
'DrydockLocalCommandInterface' => 'applications/drydock/interface/command/local',
|
||||
'DrydockLocalHostBlueprint' => 'applications/drydock/blueprint/localhost',
|
||||
'DrydockLog' => 'applications/drydock/storage/log',
|
||||
'DrydockLogController' => 'applications/drydock/controller/log',
|
||||
'DrydockLogQuery' => 'applications/drydock/query/log',
|
||||
'DrydockPhabricatorApplicationBlueprint' => 'applications/drydock/blueprint/application/phabricator',
|
||||
'DrydockRemoteHostBlueprint' => 'applications/drydock/blueprint/remotehost',
|
||||
'DrydockResource' => 'applications/drydock/storage/resource',
|
||||
'DrydockResourceAllocateController' => 'applications/drydock/controller/resourceallocate',
|
||||
'DrydockResourceListController' => 'applications/drydock/controller/resourcelist',
|
||||
'DrydockResourceStatus' => 'applications/drydock/constants/resourcestatus',
|
||||
'DrydockSSHCommandInterface' => 'applications/drydock/interface/command/ssh',
|
||||
'DrydockWebrootInterface' => 'applications/drydock/interface/webroot/base',
|
||||
'HeraldAction' => 'applications/herald/storage/action',
|
||||
'HeraldActionConfig' => 'applications/herald/config/action',
|
||||
'HeraldAllRulesController' => 'applications/herald/controller/all',
|
||||
|
@ -683,6 +690,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorObjectHandleData' => 'applications/phid/handle/data',
|
||||
'PhabricatorObjectHandleStatus' => 'applications/phid/handle/const/status',
|
||||
'PhabricatorObjectSelectorDialog' => 'view/control/objectselector',
|
||||
'PhabricatorOffsetPagedQuery' => 'infrastructure/query/offsetpaged',
|
||||
'PhabricatorOwnerPathQuery' => 'applications/owners/query/path',
|
||||
'PhabricatorOwnersController' => 'applications/owners/controller/base',
|
||||
'PhabricatorOwnersDAO' => 'applications/owners/storage/base',
|
||||
|
@ -727,6 +735,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectTransaction' => 'applications/project/storage/transaction',
|
||||
'PhabricatorProjectTransactionType' => 'applications/project/constants/transaction',
|
||||
'PhabricatorProjectUpdateController' => 'applications/project/controller/update',
|
||||
'PhabricatorQuery' => 'infrastructure/query/base',
|
||||
'PhabricatorRedirectController' => 'applications/base/controller/redirect',
|
||||
'PhabricatorRefreshCSRFController' => 'applications/auth/controller/refresh',
|
||||
'PhabricatorRemarkupRuleDifferential' => 'infrastructure/markup/remarkup/markuprule/differential',
|
||||
|
@ -1167,6 +1176,7 @@ phutil_register_library_map(array(
|
|||
'DiffusionDiffController' => 'DiffusionController',
|
||||
'DiffusionEmptyResultView' => 'DiffusionView',
|
||||
'DiffusionExternalController' => 'DiffusionController',
|
||||
'DiffusionFileContentQuery' => 'DiffusionQuery',
|
||||
'DiffusionGitBranchQuery' => 'DiffusionBranchQuery',
|
||||
'DiffusionGitBranchQueryTestCase' => 'PhabricatorTestCase',
|
||||
'DiffusionGitBrowseQuery' => 'DiffusionBrowseQuery',
|
||||
|
@ -1212,6 +1222,8 @@ phutil_register_library_map(array(
|
|||
'DiffusionURITestCase' => 'ArcanistPhutilTestCase',
|
||||
'DiffusionView' => 'AphrontView',
|
||||
'DrydockAllocatorWorker' => 'PhabricatorWorker',
|
||||
'DrydockApacheWebrootBlueprint' => 'DrydockBlueprint',
|
||||
'DrydockApacheWebrootInterface' => 'DrydockWebrootInterface',
|
||||
'DrydockCommandInterface' => 'DrydockInterface',
|
||||
'DrydockController' => 'PhabricatorController',
|
||||
'DrydockDAO' => 'PhabricatorLiskDAO',
|
||||
|
@ -1221,12 +1233,17 @@ phutil_register_library_map(array(
|
|||
'DrydockLeaseStatus' => 'DrydockConstants',
|
||||
'DrydockLocalCommandInterface' => 'DrydockCommandInterface',
|
||||
'DrydockLocalHostBlueprint' => 'DrydockBlueprint',
|
||||
'DrydockLog' => 'DrydockDAO',
|
||||
'DrydockLogController' => 'DrydockController',
|
||||
'DrydockLogQuery' => 'PhabricatorOffsetPagedQuery',
|
||||
'DrydockPhabricatorApplicationBlueprint' => 'DrydockBlueprint',
|
||||
'DrydockRemoteHostBlueprint' => 'DrydockBlueprint',
|
||||
'DrydockResource' => 'DrydockDAO',
|
||||
'DrydockResourceAllocateController' => 'DrydockController',
|
||||
'DrydockResourceListController' => 'DrydockController',
|
||||
'DrydockResourceStatus' => 'DrydockConstants',
|
||||
'DrydockSSHCommandInterface' => 'DrydockCommandInterface',
|
||||
'DrydockWebrootInterface' => 'DrydockInterface',
|
||||
'HeraldAction' => 'HeraldDAO',
|
||||
'HeraldAllRulesController' => 'HeraldController',
|
||||
'HeraldApplyTranscript' => 'HeraldDAO',
|
||||
|
@ -1468,6 +1485,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorOAuthUnlinkController' => 'PhabricatorAuthController',
|
||||
'PhabricatorObjectGraph' => 'AbstractDirectedGraph',
|
||||
'PhabricatorObjectHandleStatus' => 'PhabricatorObjectHandleConstants',
|
||||
'PhabricatorOffsetPagedQuery' => 'PhabricatorQuery',
|
||||
'PhabricatorOwnersController' => 'PhabricatorController',
|
||||
'PhabricatorOwnersDAO' => 'PhabricatorLiskDAO',
|
||||
'PhabricatorOwnersDeleteController' => 'PhabricatorOwnersController',
|
||||
|
|
|
@ -398,6 +398,7 @@ class AphrontDefaultApplicationConfiguration
|
|||
'edit/(?P<id>\d+)/' => 'DrydockhostEditController',
|
||||
),
|
||||
'lease/' => 'DrydockLeaseListController',
|
||||
'log/' => 'DrydockLogController',
|
||||
),
|
||||
|
||||
'/chatlog/' => array(
|
||||
|
|
|
@ -20,6 +20,7 @@ final class DrydockAllocator {
|
|||
|
||||
private $resourceType;
|
||||
private $lease;
|
||||
private $synchronous;
|
||||
|
||||
public function setResourceType($resource_type) {
|
||||
$this->resourceType = $resource_type;
|
||||
|
@ -30,6 +31,10 @@ final class DrydockAllocator {
|
|||
return $this->resourceType;
|
||||
}
|
||||
|
||||
public function makeSynchronous() {
|
||||
$this->synchronous = true;
|
||||
}
|
||||
|
||||
public function getPendingLease() {
|
||||
if (!$this->lease) {
|
||||
$lease = new DrydockLease();
|
||||
|
@ -44,13 +49,21 @@ final class DrydockAllocator {
|
|||
public function allocate() {
|
||||
$lease = $this->getPendingLease();
|
||||
|
||||
$task = new PhabricatorWorkerTask();
|
||||
$task->setTaskClass('DrydockAllocatorWorker');
|
||||
$task->setData(array(
|
||||
'type' => $this->getResourceType(),
|
||||
'lease' => $lease->getID(),
|
||||
));
|
||||
$task->save();
|
||||
$data = array(
|
||||
'type' => $this->getResourceType(),
|
||||
'lease' => $lease->getID(),
|
||||
);
|
||||
|
||||
if ($this->synchronous) {
|
||||
$data['synchronous'] = true;
|
||||
$worker = new DrydockAllocatorWorker($data);
|
||||
$worker->executeTask();
|
||||
} else {
|
||||
$task = new PhabricatorWorkerTask();
|
||||
$task->setTaskClass('DrydockAllocatorWorker');
|
||||
$task->setData($data);
|
||||
$task->save();
|
||||
}
|
||||
|
||||
return $lease;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/drydock/allocator/worker');
|
||||
phutil_require_module('phabricator', 'applications/drydock/constants/leasestatus');
|
||||
phutil_require_module('phabricator', 'applications/drydock/storage/lease');
|
||||
phutil_require_module('phabricator', 'infrastructure/daemon/workers/storage/task');
|
||||
|
|
|
@ -40,7 +40,6 @@ final class DrydockAllocatorWorker extends PhabricatorWorker {
|
|||
$resource = head($candidates);
|
||||
} else {
|
||||
$blueprints = DrydockBlueprint::getAllBlueprintsForResource($type);
|
||||
|
||||
foreach ($blueprints as $key => $blueprint) {
|
||||
if (!$blueprint->canAllocateResources()) {
|
||||
unset($blueprints[$key]);
|
||||
|
@ -52,11 +51,11 @@ final class DrydockAllocatorWorker extends PhabricatorWorker {
|
|||
$lease->setStatus(DrydockLeaseStatus::STATUS_BROKEN);
|
||||
$lease->save();
|
||||
|
||||
/* TODO
|
||||
$lease->updateLog(
|
||||
DrydockBlueprint::writeLog(
|
||||
null,
|
||||
$lease,
|
||||
"There are no resources of type '{$type}' available, and no ".
|
||||
"blueprints which can allocate new ones.");
|
||||
*/
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -65,12 +64,16 @@ final class DrydockAllocatorWorker extends PhabricatorWorker {
|
|||
shuffle($blueprints);
|
||||
|
||||
$blueprint = head($blueprints);
|
||||
|
||||
if (isset($data['synchronous'])) {
|
||||
$blueprint->makeSynchronous();
|
||||
}
|
||||
|
||||
$resource = $blueprint->allocateResource();
|
||||
}
|
||||
|
||||
$lease->setResourceID($resource->getID());
|
||||
$lease->setStatus(DrydockLeaseStatus::STATUS_ACTIVE);
|
||||
$lease->save();
|
||||
$blueprint = $resource->getBlueprint();
|
||||
$blueprint->acquireLease($resource, $lease);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
abstract class DrydockPhabricatorApplicationBlueprint
|
||||
extends DrydockBlueprint {
|
||||
|
||||
public function getType() {
|
||||
return 'application';
|
||||
}
|
||||
|
||||
public function canAllocateResources() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function executeAllocateResource() {
|
||||
|
||||
$resource = $this->newResourceTemplate('Phabricator');
|
||||
|
||||
$resource->setStatus(DrydockResourceStatus::STATUS_ALLOCATING);
|
||||
$resource->save();
|
||||
|
||||
$allocator = $this->getAllocator('host');
|
||||
$host = $allocator->allocate();
|
||||
|
||||
$cmd = $host->waitUntilActive()->getInterface('command');
|
||||
|
||||
$cmd->execx(<<<EOINSTALL
|
||||
yum install git &&
|
||||
mkdir -p /opt/drydock &&
|
||||
cd /opt/drydock &&
|
||||
git clone git://github.com/facebook/libphutil.git &&
|
||||
git clone git://github.com/facebook/arcanist.git &&
|
||||
git clone git://github.com/facebook/phabricator.git
|
||||
EOINSTALL
|
||||
);
|
||||
|
||||
$resource->setStatus(DrydockResourceStatus::STATUS_OPEN);
|
||||
$resource->save();
|
||||
|
||||
return $resource;
|
||||
}
|
||||
|
||||
public function getInterface(
|
||||
DrydockResource $resource,
|
||||
DrydockLease $lease,
|
||||
$type) {
|
||||
|
||||
|
||||
throw new Exception("No interface of type '{$type}'.");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/drydock/blueprint/base');
|
||||
phutil_require_module('phabricator', 'applications/drydock/constants/resourcestatus');
|
||||
|
||||
|
||||
phutil_require_source('DrydockPhabricatorApplicationBlueprint.php');
|
|
@ -18,20 +18,114 @@
|
|||
|
||||
abstract class DrydockBlueprint {
|
||||
|
||||
private $activeLease;
|
||||
private $activeResource;
|
||||
private $synchronous;
|
||||
|
||||
final public function makeSynchronous() {
|
||||
$this->synchronous = true;
|
||||
}
|
||||
|
||||
abstract public function getType();
|
||||
abstract public function getInterface(
|
||||
DrydockResource $resource,
|
||||
DrydockLease $lease,
|
||||
$type);
|
||||
|
||||
protected function executeAcquireLease(
|
||||
DrydockResource $resource,
|
||||
DrydockLease $lease) {
|
||||
return;
|
||||
}
|
||||
|
||||
protected function getAllocator($type) {
|
||||
$allocator = new DrydockAllocator();
|
||||
if ($this->synchronous) {
|
||||
$allocator->makeSynchronous();
|
||||
}
|
||||
$allocator->setResourceType($type);
|
||||
|
||||
return $allocator;
|
||||
}
|
||||
|
||||
final public function acquireLease(
|
||||
DrydockResource $resource,
|
||||
DrydockLease $lease) {
|
||||
|
||||
$this->activeResource = $resource;
|
||||
$this->activeLease = $lease;
|
||||
|
||||
$this->log('Acquiring Lease');
|
||||
try {
|
||||
$this->executeAcquireLease($resource, $lease);
|
||||
} catch (Exception $ex) {
|
||||
$this->logException($ex);
|
||||
$this->activeResource = null;
|
||||
$this->activeLease = null;
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
$lease->setResourceID($resource->getID());
|
||||
$lease->setStatus(DrydockLeaseStatus::STATUS_ACTIVE);
|
||||
$lease->save();
|
||||
|
||||
$this->activeResource = null;
|
||||
$this->activeLease = null;
|
||||
}
|
||||
|
||||
protected function logException(Exception $ex) {
|
||||
$this->log($ex->getMessage());
|
||||
}
|
||||
|
||||
protected function log($message) {
|
||||
self::writeLog(
|
||||
$this->activeResource,
|
||||
$this->activeLease,
|
||||
$message);
|
||||
}
|
||||
|
||||
public static function writeLog(
|
||||
DrydockResource $resource = null,
|
||||
DrydockLease $lease = null,
|
||||
$message) {
|
||||
|
||||
$log = id(new DrydockLog())
|
||||
->setEpoch(time())
|
||||
->setMessage($message);
|
||||
|
||||
if ($resource) {
|
||||
$log->setResourceID($resource->getID());
|
||||
}
|
||||
|
||||
if ($lease) {
|
||||
$log->setLeaseID($lease->getID());
|
||||
}
|
||||
|
||||
$log->save();
|
||||
}
|
||||
|
||||
public function canAllocateResources() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function allocateResource() {
|
||||
protected function executeAllocateResource() {
|
||||
throw new Exception("This blueprint can not allocate resources!");
|
||||
}
|
||||
|
||||
final public function allocateResource() {
|
||||
try {
|
||||
$resource = $this->executeAllocateResource();
|
||||
} catch (Exception $ex) {
|
||||
$this->logException($ex);
|
||||
$this->activeResource = null;
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
return $resource;
|
||||
}
|
||||
|
||||
public static function getAllBlueprints() {
|
||||
static $list = null;
|
||||
|
||||
|
@ -58,4 +152,19 @@ abstract class DrydockBlueprint {
|
|||
return idx($groups, $type, array());
|
||||
}
|
||||
|
||||
protected function newResourceTemplate($name) {
|
||||
$resource = new DrydockResource();
|
||||
$resource->setBlueprintClass(get_class($this));
|
||||
$resource->setType($this->getType());
|
||||
$resource->setStatus(DrydockResourceStatus::STATUS_PENDING);
|
||||
$resource->setName($name);
|
||||
$resource->save();
|
||||
|
||||
$this->activeResource = $resource;
|
||||
$this->log('New Template');
|
||||
|
||||
return $resource;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -6,6 +6,12 @@
|
|||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/drydock/allocator/resource');
|
||||
phutil_require_module('phabricator', 'applications/drydock/constants/leasestatus');
|
||||
phutil_require_module('phabricator', 'applications/drydock/constants/resourcestatus');
|
||||
phutil_require_module('phabricator', 'applications/drydock/storage/log');
|
||||
phutil_require_module('phabricator', 'applications/drydock/storage/resource');
|
||||
|
||||
phutil_require_module('phutil', 'symbols');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
|
|
@ -22,16 +22,8 @@ final class DrydockEC2HostBlueprint extends DrydockRemoteHostBlueprint {
|
|||
return true;
|
||||
}
|
||||
|
||||
public function allocateResource() {
|
||||
|
||||
echo "ALLOCATING EC2 HOST!\n";
|
||||
|
||||
$resource = new DrydockResource();
|
||||
$resource->setBlueprintClass(get_class($this));
|
||||
$resource->setType($this->getType());
|
||||
$resource->setStatus(DrydockResourceStatus::STATUS_PENDING);
|
||||
$resource->setName('EC2 Host');
|
||||
$resource->save();
|
||||
public function executeAllocateResource() {
|
||||
$resource = $this->newResourceTemplate('EC2 Host');
|
||||
|
||||
$resource->setStatus(DrydockResourceStatus::STATUS_ALLOCATING);
|
||||
$resource->save();
|
||||
|
@ -49,7 +41,9 @@ final class DrydockEC2HostBlueprint extends DrydockRemoteHostBlueprint {
|
|||
|
||||
$instance_id = (string)$xml->instancesSet[0]->item[0]->instanceId[0];
|
||||
|
||||
echo "instance id: ".$instance_id."\n";
|
||||
$this->log('Started Instance: {$instance_id}');
|
||||
$resource->setAttribute('instance.id', $instance_id);
|
||||
$resource->save();
|
||||
|
||||
$n = 1;
|
||||
do {
|
||||
|
@ -59,25 +53,23 @@ final class DrydockEC2HostBlueprint extends DrydockRemoteHostBlueprint {
|
|||
'InstanceId.1' => $instance_id,
|
||||
));
|
||||
|
||||
var_dump($xml);
|
||||
|
||||
$instance = $xml->reservationSet[0]->item[0]->instancesSet[0]->item[0];
|
||||
|
||||
$state = (string)$instance->instanceState[0]->name;
|
||||
|
||||
echo "State = {$state}\n";
|
||||
|
||||
if ($state == 'pending') {
|
||||
sleep(min($n++, 15));
|
||||
} else if ($state == 'running') {
|
||||
break;
|
||||
} else {
|
||||
// TODO: Communicate this failure.
|
||||
$this->log("EC2 host reported in unknown state '{$state}'.");
|
||||
|
||||
$resource->setStatus(DrydockResourceStatus::STATUS_BROKEN);
|
||||
$resource->save();
|
||||
}
|
||||
} while (true);
|
||||
|
||||
$this->log('Waiting for Init');
|
||||
|
||||
$n = 1;
|
||||
do {
|
||||
|
@ -87,8 +79,6 @@ final class DrydockEC2HostBlueprint extends DrydockRemoteHostBlueprint {
|
|||
'InstanceId' => $instance_id,
|
||||
));
|
||||
|
||||
var_dump($xml);
|
||||
|
||||
$item = $xml->instanceStatusSet[0]->item[0];
|
||||
|
||||
$system_status = (string)$item->systemStatus->status[0];
|
||||
|
@ -101,17 +91,15 @@ final class DrydockEC2HostBlueprint extends DrydockRemoteHostBlueprint {
|
|||
($instance_status == 'ok')) {
|
||||
break;
|
||||
} else {
|
||||
// TODO: Communicate this failure.
|
||||
$this->log(
|
||||
"EC2 system and instance status in bad states: ".
|
||||
"'{$system_status}', '{$instance_status}'.");
|
||||
|
||||
$resource->setStatus(DrydockResourceStatus::STATUS_BROKEN);
|
||||
$resource->save();
|
||||
}
|
||||
} while (true);
|
||||
|
||||
// TODO: This is a fuzz factor because sshd doesn't come up immediately
|
||||
// once EC2 reports the machine reachable. Validate that SSH is actually
|
||||
// responsive.
|
||||
sleep(120);
|
||||
|
||||
$resource->setAttributes(
|
||||
array(
|
||||
'host' => (string)$instance->dnsName,
|
||||
|
@ -119,6 +107,24 @@ final class DrydockEC2HostBlueprint extends DrydockRemoteHostBlueprint {
|
|||
'ssh-keyfile' => '/Users/epriestley/.ssh/id_ec2w',
|
||||
));
|
||||
$resource->setName($resource->getName().' ('.$instance->dnsName.')');
|
||||
$resource->save();
|
||||
|
||||
$this->log('Waiting for SSH');
|
||||
|
||||
// SSH isn't immediately responsive, so wait for it to actually come up.
|
||||
$cmd = $this->getInterface($resource, new DrydockLease(), 'command');
|
||||
$n = 1;
|
||||
do {
|
||||
list($err) = $cmd->exec('true');
|
||||
if ($err) {
|
||||
sleep(min($n++, 15));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
|
||||
$this->log('SSH OK');
|
||||
|
||||
$resource->setStatus(DrydockResourceStatus::STATUS_OPEN);
|
||||
$resource->save();
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
phutil_require_module('phabricator', 'applications/drydock/blueprint/remotehost');
|
||||
phutil_require_module('phabricator', 'applications/drydock/constants/resourcestatus');
|
||||
phutil_require_module('phabricator', 'applications/drydock/interface/command/ssh');
|
||||
phutil_require_module('phabricator', 'applications/drydock/storage/resource');
|
||||
phutil_require_module('phabricator', 'applications/drydock/storage/lease');
|
||||
phutil_require_module('phabricator', 'infrastructure/env');
|
||||
|
||||
phutil_require_module('phutil', 'future/aws/ec2');
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
final class DrydockApacheWebrootBlueprint
|
||||
extends DrydockBlueprint {
|
||||
|
||||
public function getType() {
|
||||
return 'webroot';
|
||||
}
|
||||
|
||||
public function canAllocateResources() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function executeAcquireLease(
|
||||
DrydockResource $resource,
|
||||
DrydockLease $lease) {
|
||||
|
||||
$key = Filesystem::readRandomCharacters(12);
|
||||
|
||||
$ports = $resource->getAttribute('ports', array());
|
||||
for ($ii = 2000; ; $ii++) {
|
||||
if (empty($ports[$ii])) {
|
||||
$ports[$ii] = $lease->getID();
|
||||
$port = $ii;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$resource->setAttribute('ports', $ports);
|
||||
$resource->save();
|
||||
|
||||
$host = $resource->getAttribute('host');
|
||||
|
||||
$lease->setAttribute('port', $port);
|
||||
$lease->setAttribute('key', $key);
|
||||
$lease->save();
|
||||
|
||||
$config = <<<EOCONFIG
|
||||
|
||||
Listen *:{$port}
|
||||
<VirtualHost *:{$port}>
|
||||
DocumentRoot /opt/drydock/webroot/{$key}/
|
||||
ServerName {$host}
|
||||
</VirtualHost>
|
||||
EOCONFIG;
|
||||
|
||||
$cmd = $this->getInterface($resource, $lease, 'command');
|
||||
$cmd->execx(<<<EOSETUP
|
||||
sudo mkdir -p %s &&
|
||||
sudo sh -c %s &&
|
||||
sudo /etc/init.d/httpd restart
|
||||
EOSETUP
|
||||
,
|
||||
"/opt/drydock/webroot/{$key}/",
|
||||
csprintf(
|
||||
'echo %s > %s',
|
||||
$config,
|
||||
"/etc/httpd/conf.d/drydock-{$key}.conf"));
|
||||
|
||||
$lease->setAttribute('uri', "http://{$host}:{$port}/");
|
||||
$lease->save();
|
||||
}
|
||||
|
||||
public function executeAllocateResource() {
|
||||
|
||||
$resource = $this->newResourceTemplate('Apache');
|
||||
|
||||
$resource->setStatus(DrydockResourceStatus::STATUS_ALLOCATING);
|
||||
$resource->save();
|
||||
|
||||
$allocator = $this->getAllocator('host');
|
||||
$host = $allocator->allocate();
|
||||
|
||||
$cmd = $host->waitUntilActive()->getInterface('command');
|
||||
|
||||
$cmd->execx(<<<EOINSTALL
|
||||
(yes | sudo yum install httpd) && sudo mkdir -p /opt/drydock/webroot/
|
||||
EOINSTALL
|
||||
);
|
||||
|
||||
$resource->setAttribute('lease.host', $host->getID());
|
||||
$resource->setAttribute('host', $host->getResource()->getAttribute('host'));
|
||||
|
||||
$resource->setStatus(DrydockResourceStatus::STATUS_OPEN);
|
||||
$resource->save();
|
||||
|
||||
return $resource;
|
||||
}
|
||||
|
||||
public function getInterface(
|
||||
DrydockResource $resource,
|
||||
DrydockLease $lease,
|
||||
$type) {
|
||||
|
||||
switch ($type) {
|
||||
case 'webroot':
|
||||
$iface = new DrydockApacheWebrootInterface();
|
||||
$iface->setConfiguration(
|
||||
array(
|
||||
'uri' => $lease->getAttribute('uri'),
|
||||
));
|
||||
return $iface;
|
||||
case 'command':
|
||||
$host_lease_id = $resource->getAttribute('lease.host');
|
||||
$host_lease = id(new DrydockLease())->load($host_lease_id);
|
||||
$host_lease->attachResource($host_lease->loadResource());
|
||||
return $host_lease->getInterface($type);
|
||||
}
|
||||
|
||||
|
||||
throw new Exception("No interface of type '{$type}'.");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/drydock/blueprint/base');
|
||||
phutil_require_module('phabricator', 'applications/drydock/constants/resourcestatus');
|
||||
phutil_require_module('phabricator', 'applications/drydock/interface/webroot/apache');
|
||||
phutil_require_module('phabricator', 'applications/drydock/storage/lease');
|
||||
|
||||
phutil_require_module('phutil', 'filesystem');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
phutil_require_module('phutil', 'xsprintf/csprintf');
|
||||
|
||||
|
||||
phutil_require_source('DrydockApacheWebrootBlueprint.php');
|
|
@ -43,28 +43,14 @@ abstract class DrydockController extends PhabricatorController {
|
|||
}
|
||||
|
||||
final protected function buildSideNav($selected) {
|
||||
$items = array(
|
||||
'resourcelist' => array(
|
||||
'href' => '/drydock/resource/',
|
||||
'name' => 'Resources',
|
||||
),
|
||||
'leaselist' => array(
|
||||
'href' => '/drydock/lease/',
|
||||
'name' => 'Leases',
|
||||
),
|
||||
);
|
||||
$nav = new AphrontSideNavFilterView();
|
||||
$nav->setBaseURI(new PhutilURI('/drydock/'));
|
||||
$nav->addFilter('resource', 'Resources');
|
||||
$nav->addFilter('lease', 'Leases');
|
||||
$nav->addSpacer();
|
||||
$nav->addFilter('log', 'Logs');
|
||||
|
||||
$nav = new AphrontSideNavView();
|
||||
foreach ($items as $key => $info) {
|
||||
$nav->addNavItem(
|
||||
phutil_render_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $info['href'],
|
||||
'class' => ($key == $selected ? 'aphront-side-nav-selected' : null),
|
||||
),
|
||||
phutil_escape_html($info['name'])));
|
||||
}
|
||||
$nav->selectFilter($selected, 'resource');
|
||||
|
||||
return $nav;
|
||||
}
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
phutil_require_module('phabricator', 'aphront/response/webpage');
|
||||
phutil_require_module('phabricator', 'applications/base/controller/base');
|
||||
phutil_require_module('phabricator', 'infrastructure/env');
|
||||
phutil_require_module('phabricator', 'view/layout/sidenav');
|
||||
phutil_require_module('phabricator', 'view/layout/sidenavfilter');
|
||||
|
||||
phutil_require_module('phutil', 'markup');
|
||||
phutil_require_module('phutil', 'parser/uri');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ final class DrydockLeaseListController extends DrydockController {
|
|||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$nav = $this->buildSideNav('leaselist');
|
||||
$nav = $this->buildSideNav('lease');
|
||||
|
||||
$pager = new AphrontPagerView();
|
||||
$pager->setURI(new PhutilURI('/drydock/lease/'), 'page');
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
final class DrydockLogController extends DrydockController {
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$nav = $this->buildSideNav('log');
|
||||
|
||||
$query = new DrydockLogQuery();
|
||||
|
||||
$resource_ids = $request->getStrList('resource');
|
||||
if ($resource_ids) {
|
||||
$query->withResourceIDs($resource_ids);
|
||||
}
|
||||
|
||||
$lease_ids = $request->getStrList('lease');
|
||||
if ($lease_ids) {
|
||||
$query->withLeaseIDs($lease_ids);
|
||||
}
|
||||
|
||||
$pager = new AphrontPagerView();
|
||||
$pager->setPageSize(500);
|
||||
$pager->setOffset($request->getInt('offset'));
|
||||
$pager->setURI($request->getRequestURI(), 'offset');
|
||||
|
||||
$logs = $query->executeWithPager($pager);
|
||||
|
||||
$rows = array();
|
||||
foreach ($logs as $log) {
|
||||
$rows[] = array(
|
||||
$log->getResourceID(),
|
||||
$log->getLeaseID(),
|
||||
phutil_escape_html($log->getMessage()),
|
||||
phabricator_datetime($log->getEpoch(), $user),
|
||||
);
|
||||
}
|
||||
|
||||
$table = new AphrontTableView($rows);
|
||||
$table->setHeaders(
|
||||
array(
|
||||
'Resource',
|
||||
'Lease',
|
||||
'Message',
|
||||
'Date',
|
||||
));
|
||||
$table->setColumnClasses(
|
||||
array(
|
||||
'',
|
||||
'',
|
||||
'wide',
|
||||
'',
|
||||
));
|
||||
|
||||
$panel = new AphrontPanelView();
|
||||
$panel->setHeader('Drydock Logs');
|
||||
$panel->appendChild($table);
|
||||
$panel->appendChild($pager);
|
||||
|
||||
$nav->appendChild($panel);
|
||||
|
||||
return $this->buildStandardPageResponse(
|
||||
$nav,
|
||||
array(
|
||||
'title' => 'Logs',
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
}
|
19
src/applications/drydock/controller/log/__init__.php
Normal file
19
src/applications/drydock/controller/log/__init__.php
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/drydock/controller/base');
|
||||
phutil_require_module('phabricator', 'applications/drydock/query/log');
|
||||
phutil_require_module('phabricator', 'view/control/pager');
|
||||
phutil_require_module('phabricator', 'view/control/table');
|
||||
phutil_require_module('phabricator', 'view/layout/panel');
|
||||
phutil_require_module('phabricator', 'view/utils');
|
||||
|
||||
phutil_require_module('phutil', 'markup');
|
||||
|
||||
|
||||
phutil_require_source('DrydockLogController.php');
|
|
@ -22,7 +22,7 @@ final class DrydockResourceListController extends DrydockController {
|
|||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$nav = $this->buildSideNav('resourcelist');
|
||||
$nav = $this->buildSideNav('resource');
|
||||
|
||||
$pager = new AphrontPagerView();
|
||||
$pager->setURI(new PhutilURI('/drydock/resource/'), 'page');
|
||||
|
|
|
@ -22,8 +22,11 @@ final class DrydockSSHCommandInterface extends DrydockCommandInterface {
|
|||
$argv = func_get_args();
|
||||
$full_command = call_user_func_array('csprintf', $argv);
|
||||
|
||||
// NOTE: The "-t -t" is for psuedo-tty allocation so we can "sudo" on some
|
||||
// systems, but maybe more trouble than it's worth?
|
||||
|
||||
return new ExecFuture(
|
||||
'ssh -o StrictHostKeyChecking=no -i %s %s@%s -- %s',
|
||||
'ssh -t -t -o StrictHostKeyChecking=no -i %s %s@%s -- %s',
|
||||
$this->getConfig('ssh-keyfile'),
|
||||
$this->getConfig('user'),
|
||||
$this->getConfig('host'),
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
final class DrydockApacheWebrootInterface extends DrydockWebrootInterface {
|
||||
|
||||
public function getURI() {
|
||||
return $this->getConfig('uri');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/drydock/interface/webroot/base');
|
||||
|
||||
|
||||
phutil_require_source('DrydockApacheWebrootInterface.php');
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
abstract class DrydockWebrootInterface extends DrydockInterface {
|
||||
|
||||
final public function getInterfaceType() {
|
||||
return 'webroot';
|
||||
}
|
||||
|
||||
abstract public function getURI();
|
||||
|
||||
}
|
12
src/applications/drydock/interface/webroot/base/__init__.php
Normal file
12
src/applications/drydock/interface/webroot/base/__init__.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/drydock/interface/base');
|
||||
|
||||
|
||||
phutil_require_source('DrydockWebrootInterface.php');
|
77
src/applications/drydock/query/log/DrydockLogQuery.php
Normal file
77
src/applications/drydock/query/log/DrydockLogQuery.php
Normal file
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
final class DrydockLogQuery extends PhabricatorOffsetPagedQuery {
|
||||
|
||||
private $resourceIDs;
|
||||
private $leaseIDs;
|
||||
|
||||
public function withResourceIDs(array $ids) {
|
||||
$this->resourceIDs = $ids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withLeaseIDs(array $ids) {
|
||||
$this->leaseIDs = $ids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function execute() {
|
||||
$table = new DrydockLog();
|
||||
$conn_r = $table->establishConnection('r');
|
||||
|
||||
$where = $this->buildWhereClause($conn_r);
|
||||
$order = $this->buildOrderClause($conn_r);
|
||||
$limit = $this->buildLimitClause($conn_r);
|
||||
|
||||
$data = queryfx_all(
|
||||
$conn_r,
|
||||
'SELECT log.* FROM %T log %Q %Q %Q',
|
||||
$table->getTableName(),
|
||||
$where,
|
||||
$order,
|
||||
$limit);
|
||||
|
||||
return $table->loadAllFromArray($data);
|
||||
}
|
||||
|
||||
private function buildWhereClause($conn_r) {
|
||||
$where = array();
|
||||
|
||||
if ($this->resourceIDs) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'resourceID IN (%Ld)',
|
||||
$this->resourceIDs);
|
||||
}
|
||||
|
||||
if ($this->leaseIDs) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'leaseID IN (%Ld)',
|
||||
$this->leaseIDs);
|
||||
}
|
||||
|
||||
return $this->formatWhereClause($where);
|
||||
}
|
||||
|
||||
private function buildOrderClause($conn_r) {
|
||||
return 'ORDER BY log.epoch DESC';
|
||||
}
|
||||
|
||||
}
|
15
src/applications/drydock/query/log/__init__.php
Normal file
15
src/applications/drydock/query/log/__init__.php
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/drydock/storage/log');
|
||||
phutil_require_module('phabricator', 'infrastructure/query/offsetpaged');
|
||||
phutil_require_module('phabricator', 'storage/qsprintf');
|
||||
phutil_require_module('phabricator', 'storage/queryfx');
|
||||
|
||||
|
||||
phutil_require_source('DrydockLogQuery.php');
|
|
@ -36,6 +36,15 @@ final class DrydockLease extends DrydockDAO {
|
|||
) + parent::getConfiguration();
|
||||
}
|
||||
|
||||
public function setAttribute($key, $value) {
|
||||
$this->attributes[$key] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAttribute($key, $default = null) {
|
||||
return idx($this->attributes, $key, $default);
|
||||
}
|
||||
|
||||
public function generatePHID() {
|
||||
return PhabricatorPHID::generateNewPHID(
|
||||
PhabricatorPHIDConstants::PHID_TYPE_DRYL);
|
||||
|
@ -87,6 +96,7 @@ final class DrydockLease extends DrydockDAO {
|
|||
}
|
||||
|
||||
public function waitUntilActive() {
|
||||
$this->reload();
|
||||
while (true) {
|
||||
switch ($this->status) {
|
||||
case DrydockLeaseStatus::STATUS_ACTIVE:
|
||||
|
|
32
src/applications/drydock/storage/log/DrydockLog.php
Normal file
32
src/applications/drydock/storage/log/DrydockLog.php
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
final class DrydockLog extends DrydockDAO {
|
||||
|
||||
protected $resourceID;
|
||||
protected $leaseID;
|
||||
protected $epoch;
|
||||
protected $message;
|
||||
|
||||
public function getConfiguration() {
|
||||
return array(
|
||||
self::CONFIG_TIMESTAMPS => false,
|
||||
) + parent::getConfiguration();
|
||||
}
|
||||
|
||||
}
|
12
src/applications/drydock/storage/log/__init__.php
Normal file
12
src/applications/drydock/storage/log/__init__.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/drydock/storage/base');
|
||||
|
||||
|
||||
phutil_require_source('DrydockLog.php');
|
|
@ -29,7 +29,6 @@ final class DrydockResource extends DrydockDAO {
|
|||
protected $capabilities = array();
|
||||
protected $ownerPHID;
|
||||
|
||||
|
||||
private $blueprint;
|
||||
|
||||
public function getConfiguration() {
|
||||
|
@ -51,6 +50,11 @@ final class DrydockResource extends DrydockDAO {
|
|||
return idx($this->attributes, $key, $default);
|
||||
}
|
||||
|
||||
public function setAttribute($key, $value) {
|
||||
$this->attributes[$key] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCapability($key, $default = null) {
|
||||
return idx($this->capbilities, $key, $default);
|
||||
}
|
||||
|
|
30
src/infrastructure/query/base/PhabricatorQuery.php
Normal file
30
src/infrastructure/query/base/PhabricatorQuery.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
abstract class PhabricatorQuery {
|
||||
|
||||
abstract public function execute();
|
||||
|
||||
final protected function formatWhereClause(array $parts) {
|
||||
if (!$parts) {
|
||||
return '';
|
||||
}
|
||||
return 'WHERE ('.implode(') AND (', $parts).')';
|
||||
}
|
||||
|
||||
}
|
10
src/infrastructure/query/base/__init__.php
Normal file
10
src/infrastructure/query/base/__init__.php
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorQuery.php');
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A query class which uses offset/limit paging. Provides logic and accessors
|
||||
* for offsets and limits.
|
||||
*/
|
||||
abstract class PhabricatorOffsetPagedQuery extends PhabricatorQuery {
|
||||
|
||||
private $offset;
|
||||
private $limit;
|
||||
|
||||
final public function setOffset($offset) {
|
||||
$this->offset = $offset;
|
||||
return $this;
|
||||
}
|
||||
|
||||
final public function setLimit($limit) {
|
||||
$this->limit = $limit;
|
||||
return $this;
|
||||
}
|
||||
|
||||
final protected function buildLimitClause(AphrontDatabaseConnection $conn_r) {
|
||||
if ($this->limit && $this->offset) {
|
||||
return qsprintf($conn_r, 'LIMIT %d, %d', $this->offset, $this->limit);
|
||||
} else if ($this->limit) {
|
||||
return qsprintf($conn_r, 'LIMIT %d', $this->limit);
|
||||
} else if ($this->offset) {
|
||||
return qsprintf($conn_r, 'LIMIT %d, %d', $this->offset, PHP_INT_MAX);
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
final public function executeWithPager(AphrontPagerView $pager) {
|
||||
$this->setLimit($pager->getPageSize() + 1);
|
||||
$this->setOffset($pager->getOffset());
|
||||
|
||||
$results = $this->execute();
|
||||
|
||||
return $pager->sliceResults($results);
|
||||
}
|
||||
|
||||
}
|
13
src/infrastructure/query/offsetpaged/__init__.php
Normal file
13
src/infrastructure/query/offsetpaged/__init__.php
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'infrastructure/query/base');
|
||||
phutil_require_module('phabricator', 'storage/qsprintf');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorOffsetPagedQuery.php');
|
Loading…
Reference in a new issue