mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-09 16:32:39 +01:00
Drydock Rough Cut
Summary: Rough cut of Drydock. This is very basic and doesn't do much of use yet (it //does// allocate EC2 machines as host resources and expose interfaces to them), but I think the overall structure is more or less reasonable. == Interfaces Vision: Applications interact with Drydock resources through DrydockInterfaces, like **command**, **filesystem** and **httpd** interfaces. Each interface allows applications to perform some kind of operation on the resource, like executing commands, reading/writing files, or configuring a web server. Interfaces have a concrete, specific API: // Filesystem Interface $fs = $lease->getInterface('filesystem'); // Constants, some day? $fs->writeFile('index.html', 'hello world!'); // Command Interface $cmd = $lease->getInterface('command'); echo $cmd->execx('uptime'); // HTTPD Interface $httpd = $lease->getInterface('httpd'); $httpd->restart(); Interfaces are mostly just stock, although installs might add new interfaces if they expose different ways to interact with resources (for instance, a resource might want to expose a new 'MongoDB' interface or whatever). Currently: We have like part of a command interface. == Leases Vision: Leases keep track of which resources are in use, and what they're being used for. They allow us to know when we need to allocate more resources (too many sandcastles on the existing hosts, e.g.) and when we can release resources (because they are no longer being used). They also give applications something to hold while resources are being allocated. // EXAMPLE: How this should work some day. $allocator = new DrydockAllocator(); $allocator->setResourceType('sandcastle'); $allocator->setAttributes( array( 'diffID' => $diff->getID(), )); $lease = $allocator->allocate(); $diff->setSandcastleLeaseID($lease->getID()); // ... if ($lease->getStatus() == DrydockLeaseStatus::STATUS_ACTIVE) { $sandcastle_link = $lease->getInterface('httpd')->getURI('/'); } else { $sandcastle_link = 'Still building your sandcastle...'; } echo "Sandcastle for this diff: ".$sandcastle_link; // EXAMPLE: How this actually works now. $allocator = new DrydockAllocator(); $allocator->setResourceType('host'); // NOTE: Allocation is currently synchronous but will be task-driven soon. $lease = $allocator->allocate(); Leases are completely stock, installs will not define new lease types. Currently: Leases exist and work but are very very basic. == Resources Vision: Resources represent some actual thing we've put somewhere, whether it's a host, a block of storage, a webroot, or whatever else. Applications interact through resources by acquiring leases to them, and then getting interfaces through these leases. The lease acquisition process has a side effect of allocating new resources if a lease can't be acquired on existing resources (e.g., the application wants storage but all storage resources are full) and things are configured to autoscale. Resources may themselves acquire leases in order to allocate. For instance, a storage resource might first acquire a lease to a host resource. A 'test scaffold' resource might lease a storage resource and a mysql resource. Not all resources are auto-allocate: the entry-level version of Drydock is that you manually allocate a couple boxes and configure them through the web console. Then, e.g., 'storage' / 'webroot' resources allocate on top of them, but the host pool itself does not autoscale. Resources are completely stock, they are abstract shells representing any arbitrary thing. Currently: Resource exist ('host' only) but are very very basic. == Blueprints Vision: Blueprints contain instructions for building interfaces to, (possibly) allocating, updating, managing, and destroying a specific type of resource in a specific location. One way to think of them is that they are scripts for creating and deleting resources. For example, the LocalHost, RemoteHost and EC2Host blueprints can all manage 'host' resources. Eventually, we will support more types of resources (storage, webroot, sandcastle, test scaffold, phacility deployment) and more providers for resource types, some of which will be in the Phabricator mainline and some of which will be custom. Blueprints are very custom and specific to application types, so installs will define new blueprints if they are making significant use of Drydock. Currently: They exist but have few capabilities. The stock blueprints do nearly nothing useful. There is a technically functional blueprint for host allocation in EC2. == Allocator This is just the actual code to execute the lease acquisition process. Test Plan: Ran "drydock_control.php" script, it allocated a machine in EC2, acquired a lease on it, interfaced with it, and then released the lease. Ran it again, got a fresh lease on the existing resource. Reviewers: btrahan, jungejason Reviewed By: btrahan CC: aran Differential Revision: https://secure.phabricator.com/D1454
This commit is contained in:
parent
ff339e152e
commit
d1ee08b2df
45 changed files with 1655 additions and 2 deletions
|
@ -671,6 +671,14 @@ return array(
|
|||
// projects that want to expose an activity feed on the project homepage.
|
||||
'feed.public' => false,
|
||||
|
||||
|
||||
// -- Drydock --------------------------------------------------------------- //
|
||||
|
||||
// If you want to use Drydock's builtin EC2 Blueprints, configure your AWS
|
||||
// EC2 credentials here.
|
||||
'amazon-ec2.access-key' => null,
|
||||
'amazon-ec2.secret-key' => null,
|
||||
|
||||
// -- Customization --------------------------------------------------------- //
|
||||
|
||||
// Paths to additional phutil libraries to load.
|
||||
|
|
29
resources/sql/patches/099.drydock.sql
Normal file
29
resources/sql/patches/099.drydock.sql
Normal file
|
@ -0,0 +1,29 @@
|
|||
CREATE DATABASE IF NOT EXISTS phabricator_drydock;
|
||||
|
||||
CREATE TABLE phabricator_drydock.drydock_resource (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
phid VARCHAR(64) BINARY NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
ownerPHID varchar(64) BINARY,
|
||||
status INT UNSIGNED NOT NULL,
|
||||
blueprintClass VARCHAR(255) NOT NULL,
|
||||
type VARCHAR(64) NOT NULL,
|
||||
attributes LONGBLOB NOT NULL,
|
||||
capabilities LONGBLOB NOT NULL,
|
||||
dateCreated INT UNSIGNED NOT NULL,
|
||||
dateModified INT UNSIGNED NOT NULL,
|
||||
UNIQUE KEY (phid)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE phabricator_drydock.drydock_lease (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
phid VARCHAR(64) BINARY NOT NULL,
|
||||
resourceID INT UNSIGNED,
|
||||
status INT UNSIGNED NOT NULL,
|
||||
until INT UNSIGNED,
|
||||
ownerPHID VARCHAR(64) BINARY,
|
||||
attributes LONGBLOB NOT NULL,
|
||||
dateCreated INT UNSIGNED NOT NULL,
|
||||
dateModified INT UNSIGNED NOT NULL,
|
||||
UNIQUE KEY (phid)
|
||||
) ENGINE=InnoDB;
|
42
scripts/drydock/drydock_control.php
Executable file
42
scripts/drydock/drydock_control.php
Executable file
|
@ -0,0 +1,42 @@
|
|||
#!/usr/bin/env php
|
||||
<?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.
|
||||
*/
|
||||
|
||||
$root = dirname(dirname(dirname(__FILE__)));
|
||||
require_once $root.'/scripts/__init_script__.php';
|
||||
|
||||
phutil_require_module('phutil', 'console');
|
||||
phutil_require_module('phutil', 'future/exec');
|
||||
|
||||
PhutilServiceProfiler::installEchoListener();
|
||||
|
||||
$allocator = new DrydockAllocator();
|
||||
$allocator->setResourceType('host');
|
||||
$lease = $allocator->allocate();
|
||||
|
||||
$i_file = $lease->getInterface('command');
|
||||
|
||||
list($stdout) = $i_file->execx('ls / ; echo -- ; uptime ; echo -- ; uname -n');
|
||||
echo $stdout;
|
||||
|
||||
|
||||
$lease->release();
|
||||
|
||||
|
||||
//$i_http = $lease->getInterface('httpd');
|
||||
//echo $i_http->getURI('/index.html')."\n";
|
|
@ -311,6 +311,25 @@ phutil_register_library_map(array(
|
|||
'DiffusionSymbolController' => 'applications/diffusion/controller/symbol',
|
||||
'DiffusionSymbolQuery' => 'applications/diffusion/query/symbol',
|
||||
'DiffusionView' => 'applications/diffusion/view/base',
|
||||
'DrydockAllocator' => 'applications/drydock/allocator/resource',
|
||||
'DrydockBlueprint' => 'applications/drydock/blueprint/base',
|
||||
'DrydockCommandInterface' => 'applications/drydock/interface/command/base',
|
||||
'DrydockConstants' => 'applications/drydock/constants/base',
|
||||
'DrydockController' => 'applications/drydock/controller/base',
|
||||
'DrydockDAO' => 'applications/drydock/storage/base',
|
||||
'DrydockEC2HostBlueprint' => 'applications/drydock/blueprint/ec2host',
|
||||
'DrydockInterface' => 'applications/drydock/interface/base',
|
||||
'DrydockLease' => 'applications/drydock/storage/lease',
|
||||
'DrydockLeaseListController' => 'applications/drydock/controller/leaselist',
|
||||
'DrydockLeaseStatus' => 'applications/drydock/constants/leasestatus',
|
||||
'DrydockLocalCommandInterface' => 'applications/drydock/interface/command/local',
|
||||
'DrydockLocalHostBlueprint' => 'applications/drydock/blueprint/localhost',
|
||||
'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',
|
||||
'HeraldAction' => 'applications/herald/storage/action',
|
||||
'HeraldActionConfig' => 'applications/herald/config/action',
|
||||
'HeraldAllRulesController' => 'applications/herald/controller/all',
|
||||
|
@ -1039,6 +1058,21 @@ phutil_register_library_map(array(
|
|||
'DiffusionSvnRequest' => 'DiffusionRequest',
|
||||
'DiffusionSymbolController' => 'DiffusionController',
|
||||
'DiffusionView' => 'AphrontView',
|
||||
'DrydockCommandInterface' => 'DrydockInterface',
|
||||
'DrydockController' => 'PhabricatorController',
|
||||
'DrydockDAO' => 'PhabricatorLiskDAO',
|
||||
'DrydockEC2HostBlueprint' => 'DrydockRemoteHostBlueprint',
|
||||
'DrydockLease' => 'DrydockDAO',
|
||||
'DrydockLeaseListController' => 'DrydockController',
|
||||
'DrydockLeaseStatus' => 'DrydockConstants',
|
||||
'DrydockLocalCommandInterface' => 'DrydockCommandInterface',
|
||||
'DrydockLocalHostBlueprint' => 'DrydockBlueprint',
|
||||
'DrydockRemoteHostBlueprint' => 'DrydockBlueprint',
|
||||
'DrydockResource' => 'DrydockDAO',
|
||||
'DrydockResourceAllocateController' => 'DrydockController',
|
||||
'DrydockResourceListController' => 'DrydockController',
|
||||
'DrydockResourceStatus' => 'DrydockConstants',
|
||||
'DrydockSSHCommandInterface' => 'DrydockCommandInterface',
|
||||
'HeraldAction' => 'HeraldDAO',
|
||||
'HeraldAllRulesController' => 'HeraldController',
|
||||
'HeraldApplyTranscript' => 'HeraldDAO',
|
||||
|
|
|
@ -380,6 +380,18 @@ class AphrontDefaultApplicationConfiguration
|
|||
'/calendar/' => array(
|
||||
'$' => 'PhabricatorCalendarBrowseController',
|
||||
),
|
||||
|
||||
'/drydock/' => array(
|
||||
'$' => 'DrydockResourceListController',
|
||||
'resource/$' => 'DrydockResourceListController',
|
||||
'resource/allocate/$' => 'DrydockResourceAllocateController',
|
||||
'host/' => array(
|
||||
'$' => 'DrydockHostListController',
|
||||
'edit/$' => 'DrydockHostEditController',
|
||||
'edit/(?P<id>\d+)/$' => 'DrydockhostEditController',
|
||||
),
|
||||
'lease/$' => 'DrydockLeaseListController',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
<?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 DrydockAllocator {
|
||||
|
||||
private $resourceType;
|
||||
private $lease;
|
||||
|
||||
public function setResourceType($resource_type) {
|
||||
$this->resourceType = $resource_type;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getResourceType() {
|
||||
return $this->resourceType;
|
||||
}
|
||||
|
||||
public function getPendingLease() {
|
||||
if (!$this->lease) {
|
||||
$lease = new DrydockLease();
|
||||
$lease->setStatus(DrydockLeaseStatus::STATUS_PENDING);
|
||||
$lease->save();
|
||||
|
||||
$this->lease = $lease;
|
||||
}
|
||||
return $lease;
|
||||
}
|
||||
|
||||
public function allocate() {
|
||||
$type = $this->getResourceType();
|
||||
|
||||
$candidates = id(new DrydockResource())->loadAllWhere(
|
||||
'type = %s AND status = %s',
|
||||
$type,
|
||||
DrydockResourceStatus::STATUS_OPEN);
|
||||
|
||||
if ($candidates) {
|
||||
shuffle($candidates);
|
||||
$resource = head($candidates);
|
||||
} else {
|
||||
$blueprints = DrydockBlueprint::getAllBlueprintsForResource($type);
|
||||
|
||||
foreach ($blueprints as $key => $blueprint) {
|
||||
if (!$blueprint->canAllocateResources()) {
|
||||
unset($blueprints[$key]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$blueprints) {
|
||||
throw new Exception(
|
||||
"There are no valid existing '{$type}' resources, and no valid ".
|
||||
"blueprints to build new ones.");
|
||||
}
|
||||
|
||||
// TODO: Rank intelligently.
|
||||
shuffle($blueprints);
|
||||
|
||||
$blueprint = head($blueprints);
|
||||
$resource = $blueprint->allocateResource();
|
||||
}
|
||||
|
||||
$lease = $this->getPendingLease();
|
||||
$lease->setResourceID($resource->getID());
|
||||
$lease->setStatus(DrydockLeaseStatus::STATUS_ACTIVE);
|
||||
$lease->save();
|
||||
|
||||
$lease->attachResource($resource);
|
||||
|
||||
return $lease;
|
||||
}
|
||||
|
||||
}
|
18
src/applications/drydock/allocator/resource/__init__.php
Normal file
18
src/applications/drydock/allocator/resource/__init__.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?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/leasestatus');
|
||||
phutil_require_module('phabricator', 'applications/drydock/constants/resourcestatus');
|
||||
phutil_require_module('phabricator', 'applications/drydock/storage/lease');
|
||||
phutil_require_module('phabricator', 'applications/drydock/storage/resource');
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('DrydockAllocator.php');
|
64
src/applications/drydock/blueprint/base/DrydockBlueprint.php
Normal file
64
src/applications/drydock/blueprint/base/DrydockBlueprint.php
Normal file
|
@ -0,0 +1,64 @@
|
|||
<?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 DrydockBlueprint {
|
||||
|
||||
abstract public function getType();
|
||||
abstract public function getInterface(
|
||||
DrydockResource $resource,
|
||||
DrydockLease $lease,
|
||||
$type);
|
||||
|
||||
public function canAllocateResources() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function allocateResource() {
|
||||
throw new Exception("This blueprint can not allocate resources!");
|
||||
}
|
||||
|
||||
public static function getAllBlueprints() {
|
||||
static $list = null;
|
||||
|
||||
if ($list === null) {
|
||||
$blueprints = id(new PhutilSymbolLoader())
|
||||
->setType('class')
|
||||
->setAncestorClass('DrydockBlueprint')
|
||||
->selectAndLoadSymbols();
|
||||
$list = ipull($blueprints, 'name', 'name');
|
||||
foreach ($list as $class_name => $ignored) {
|
||||
$reflection = new ReflectionClass($class_name);
|
||||
if ($reflection->isAbstract()) {
|
||||
continue;
|
||||
}
|
||||
$list[$class_name] = newv($class_name, array());
|
||||
}
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
public static function getAllBlueprintsForResource($type) {
|
||||
static $groups = null;
|
||||
if ($groups === null) {
|
||||
$groups = mgroup(self::getAllBlueprints(), 'getType');
|
||||
}
|
||||
return idx($groups, $type, array());
|
||||
}
|
||||
|
||||
}
|
13
src/applications/drydock/blueprint/base/__init__.php
Normal file
13
src/applications/drydock/blueprint/base/__init__.php
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phutil', 'symbols');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('DrydockBlueprint.php');
|
|
@ -0,0 +1,157 @@
|
|||
<?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.
|
||||
*/
|
||||
|
||||
class DrydockEC2HostBlueprint extends DrydockRemoteHostBlueprint {
|
||||
|
||||
public function canAllocateResources() {
|
||||
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();
|
||||
|
||||
$resource->setStatus(DrydockResourceStatus::STATUS_ALLOCATING);
|
||||
$resource->save();
|
||||
|
||||
$xml = $this->executeEC2Query(
|
||||
'RunInstances',
|
||||
array(
|
||||
'ImageId' => 'ami-c7c99982',
|
||||
'MinCount' => 1,
|
||||
'MaxCount' => 1,
|
||||
'KeyName' => 'ec2wc',
|
||||
'SecurityGroupId.1' => 'sg-6bffff2e',
|
||||
'InstanceType' => 't1.micro',
|
||||
));
|
||||
|
||||
$instance_id = (string)$xml->instancesSet[0]->item[0]->instanceId[0];
|
||||
|
||||
echo "instance id: ".$instance_id."\n";
|
||||
|
||||
$n = 1;
|
||||
do {
|
||||
$xml = $this->executeEC2Query(
|
||||
'DescribeInstances',
|
||||
array(
|
||||
'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.
|
||||
$resource->setStatus(DrydockResourceStatus::STATUS_BROKEN);
|
||||
$resource->save();
|
||||
}
|
||||
} while (true);
|
||||
|
||||
|
||||
$n = 1;
|
||||
do {
|
||||
$xml = $this->executeEC2Query(
|
||||
'DescribeInstanceStatus',
|
||||
array(
|
||||
'InstanceId' => $instance_id,
|
||||
));
|
||||
|
||||
var_dump($xml);
|
||||
|
||||
$item = $xml->instanceStatusSet[0]->item[0];
|
||||
|
||||
$system_status = (string)$item->systemStatus->status[0];
|
||||
$instance_status = (string)$item->instanceStatus->status[0];
|
||||
|
||||
if (($system_status == 'initializing') ||
|
||||
($instance_status == 'initializing')) {
|
||||
sleep(min($n++, 15));
|
||||
} else if (($system_status == 'ok') &&
|
||||
($instance_status == 'ok')) {
|
||||
break;
|
||||
} else {
|
||||
// TODO: Communicate this failure.
|
||||
$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,
|
||||
'user' => 'ec2-user',
|
||||
'ssh-keyfile' => '/Users/epriestley/.ssh/id_ec2w',
|
||||
));
|
||||
$resource->setName($resource->getName().' ('.$instance->dnsName.')');
|
||||
$resource->setStatus(DrydockResourceStatus::STATUS_OPEN);
|
||||
$resource->save();
|
||||
|
||||
return $resource;
|
||||
}
|
||||
|
||||
public function getInterface(
|
||||
DrydockResource $resource,
|
||||
DrydockLease $lease,
|
||||
$type) {
|
||||
|
||||
switch ($type) {
|
||||
case 'command':
|
||||
$ssh = new DrydockSSHCommandInterface();
|
||||
$ssh->setConfiguration(
|
||||
array(
|
||||
'host' => $resource->getAttribute('host'),
|
||||
'user' => $resource->getAttribute('user'),
|
||||
'ssh-keyfile' => $resource->getAttribute('ssh-keyfile'),
|
||||
));
|
||||
return $ssh;
|
||||
}
|
||||
|
||||
throw new Exception("No interface of type '{$type}'.");
|
||||
}
|
||||
|
||||
private function executeEC2Query($action, array $params) {
|
||||
$future = new PhutilAWSEC2Future();
|
||||
$future->setAWSKeys(
|
||||
PhabricatorEnv::getEnvConfig('amazon-ec2.access-key'),
|
||||
PhabricatorEnv::getEnvConfig('amazon-ec2.secret-key'));
|
||||
$future->setRawAWSQuery($action, $params);
|
||||
return $future->resolve();
|
||||
}
|
||||
|
||||
}
|
18
src/applications/drydock/blueprint/ec2host/__init__.php
Normal file
18
src/applications/drydock/blueprint/ec2host/__init__.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
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', 'infrastructure/env');
|
||||
|
||||
phutil_require_module('phutil', 'future/aws/ec2');
|
||||
|
||||
|
||||
phutil_require_source('DrydockEC2HostBlueprint.php');
|
|
@ -0,0 +1,38 @@
|
|||
<?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 DrydockLocalHostBlueprint extends DrydockBlueprint {
|
||||
|
||||
public function getType() {
|
||||
return 'host';
|
||||
}
|
||||
|
||||
public function getInterface(
|
||||
DrydockResource $resource,
|
||||
DrydockLease $lease,
|
||||
$type) {
|
||||
|
||||
switch ($type) {
|
||||
case 'command':
|
||||
return new DrydockLocalCommandInterface();
|
||||
}
|
||||
|
||||
throw new Exception("No interface of type '{$type}'.");
|
||||
}
|
||||
|
||||
}
|
13
src/applications/drydock/blueprint/localhost/__init__.php
Normal file
13
src/applications/drydock/blueprint/localhost/__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', 'applications/drydock/blueprint/base');
|
||||
phutil_require_module('phabricator', 'applications/drydock/interface/command/local');
|
||||
|
||||
|
||||
phutil_require_source('DrydockLocalHostBlueprint.php');
|
|
@ -0,0 +1,45 @@
|
|||
<?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.
|
||||
*/
|
||||
|
||||
class DrydockRemoteHostBlueprint extends DrydockBlueprint {
|
||||
|
||||
public function getType() {
|
||||
return 'host';
|
||||
}
|
||||
|
||||
public function getInterface(
|
||||
DrydockResource $resource,
|
||||
DrydockLease $lease,
|
||||
$type) {
|
||||
|
||||
switch ($type) {
|
||||
case 'command':
|
||||
$ssh = new DrydockSSHCommandInterface();
|
||||
$ssh->setConfiguration(
|
||||
array(
|
||||
'host' => 'secure.phabricator.com',
|
||||
'user' => 'ec2-user',
|
||||
'ssh-keyfile' => '/Users/epriestley/.ssh/id_ec2w',
|
||||
));
|
||||
return $ssh;
|
||||
}
|
||||
|
||||
throw new Exception("No interface of type '{$type}'.");
|
||||
}
|
||||
|
||||
}
|
13
src/applications/drydock/blueprint/remotehost/__init__.php
Normal file
13
src/applications/drydock/blueprint/remotehost/__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', 'applications/drydock/blueprint/base');
|
||||
phutil_require_module('phabricator', 'applications/drydock/interface/command/ssh');
|
||||
|
||||
|
||||
phutil_require_source('DrydockRemoteHostBlueprint.php');
|
21
src/applications/drydock/constants/base/DrydockConstants.php
Normal file
21
src/applications/drydock/constants/base/DrydockConstants.php
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?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 DrydockConstants {
|
||||
|
||||
}
|
10
src/applications/drydock/constants/base/__init__.php
Normal file
10
src/applications/drydock/constants/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('DrydockConstants.php');
|
|
@ -0,0 +1,39 @@
|
|||
<?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 DrydockLeaseStatus extends DrydockConstants {
|
||||
|
||||
const STATUS_PENDING = 0;
|
||||
const STATUS_ACTIVE = 1;
|
||||
const STATUS_RELEASED = 2;
|
||||
const STATUS_BROKEN = 3;
|
||||
const STATUS_EXPIRED = 4;
|
||||
|
||||
public static function getNameForStatus($status) {
|
||||
static $map = array(
|
||||
self::STATUS_PENDING => 'Pending',
|
||||
self::STATUS_ACTIVE => 'Active',
|
||||
self::STATUS_RELEASED => 'Released',
|
||||
self::STATUS_BROKEN => 'Broken',
|
||||
self::STATUS_EXPIRED => 'Expired',
|
||||
);
|
||||
|
||||
return idx($map, $status, 'Unknown');
|
||||
}
|
||||
|
||||
}
|
14
src/applications/drydock/constants/leasestatus/__init__.php
Normal file
14
src/applications/drydock/constants/leasestatus/__init__.php
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/drydock/constants/base');
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('DrydockLeaseStatus.php');
|
|
@ -0,0 +1,41 @@
|
|||
<?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 DrydockResourceStatus extends DrydockConstants {
|
||||
|
||||
const STATUS_PENDING = 0;
|
||||
const STATUS_ALLOCATING = 1;
|
||||
const STATUS_OPEN = 2;
|
||||
const STATUS_CLOSED = 3;
|
||||
const STATUS_BROKEN = 4;
|
||||
const STATUS_DESTROYED = 5;
|
||||
|
||||
public static function getNameForStatus($status) {
|
||||
static $map = array(
|
||||
self::STATUS_PENDING => 'Pending',
|
||||
self::STATUS_ALLOCATING => 'Pending',
|
||||
self::STATUS_OPEN => 'Open',
|
||||
self::STATUS_CLOSED => 'Closed',
|
||||
self::STATUS_BROKEN => 'Broken',
|
||||
self::STATUS_DESTROYED => 'Destroyed',
|
||||
);
|
||||
|
||||
return idx($map, $status, 'Unknown');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/drydock/constants/base');
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('DrydockResourceStatus.php');
|
|
@ -0,0 +1,72 @@
|
|||
<?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 DrydockController extends PhabricatorController {
|
||||
|
||||
public function buildStandardPageResponse($view, array $data) {
|
||||
|
||||
$page = $this->buildStandardPageView();
|
||||
|
||||
$page->setApplicationName('Drydock');
|
||||
$page->setBaseURI('/drydock/');
|
||||
$page->setTitle(idx($data, 'title'));
|
||||
$page->setGlyph("\xE2\x98\x82");
|
||||
|
||||
$page->appendChild($view);
|
||||
|
||||
$help_uri = PhabricatorEnv::getDoclink('article/Drydock_User_Guide.html');
|
||||
$page->setTabs(
|
||||
array(
|
||||
'help' => array(
|
||||
'name' => 'Help',
|
||||
'href' => $help_uri,
|
||||
),
|
||||
), null);
|
||||
|
||||
$response = new AphrontWebpageResponse();
|
||||
return $response->setContent($page->render());
|
||||
}
|
||||
|
||||
final protected function buildSideNav($selected) {
|
||||
$items = array(
|
||||
'resourcelist' => array(
|
||||
'href' => '/drydock/resource/',
|
||||
'name' => 'Resources',
|
||||
),
|
||||
'leaselist' => array(
|
||||
'href' => '/drydock/lease/',
|
||||
'name' => 'Leases',
|
||||
),
|
||||
);
|
||||
|
||||
$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'])));
|
||||
}
|
||||
|
||||
return $nav;
|
||||
}
|
||||
|
||||
}
|
18
src/applications/drydock/controller/base/__init__.php
Normal file
18
src/applications/drydock/controller/base/__init__.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
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('phutil', 'markup');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('DrydockController.php');
|
|
@ -0,0 +1,99 @@
|
|||
<?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 DrydockLeaseListController extends DrydockController {
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$nav = $this->buildSideNav('leaselist');
|
||||
|
||||
$pager = new AphrontPagerView();
|
||||
$pager->setURI(new PhutilURI('/drydock/lease/'), 'page');
|
||||
|
||||
$data = id(new DrydockLease())->loadAllWhere(
|
||||
'1 = 1 ORDER BY id DESC LIMIT %d, %d',
|
||||
$pager->getOffset(),
|
||||
$pager->getPageSize() + 1);
|
||||
$data = $pager->sliceResults($data);
|
||||
|
||||
$phids = mpull($data, 'getOwnerPHID');
|
||||
$handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
|
||||
|
||||
$resource_ids = mpull($data, 'getResourceID');
|
||||
$resources = array();
|
||||
if ($resource_ids) {
|
||||
$resources = id(new DrydockResource())->loadAllWhere(
|
||||
'id IN (%Ld)',
|
||||
$resource_ids);
|
||||
}
|
||||
|
||||
$rows = array();
|
||||
foreach ($data as $lease) {
|
||||
$resource = idx($resources, $lease->getResourceID());
|
||||
$rows[] = array(
|
||||
$lease->getID(),
|
||||
DrydockLeaseStatus::getNameForStatus($lease->getStatus()),
|
||||
($lease->getOwnerPHID()
|
||||
? $handles[$lease->getOwnerPHID()]->renderLink()
|
||||
: null),
|
||||
$lease->getResourceID(),
|
||||
($resource
|
||||
? phutil_escape_html($resource->getName())
|
||||
: null),
|
||||
phabricator_datetime($lease->getDateCreated(), $user),
|
||||
);
|
||||
}
|
||||
|
||||
$table = new AphrontTableView($rows);
|
||||
$table->setHeaders(
|
||||
array(
|
||||
'ID',
|
||||
'Status',
|
||||
'Owner',
|
||||
'Resource ID',
|
||||
'Resource',
|
||||
'Created',
|
||||
));
|
||||
$table->setColumnClasses(
|
||||
array(
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'wide pri',
|
||||
'right',
|
||||
));
|
||||
|
||||
$panel = new AphrontPanelView();
|
||||
$panel->setHeader('Drydock Leases');
|
||||
|
||||
$panel->appendChild($table);
|
||||
$panel->appendChild($pager);
|
||||
|
||||
$nav->appendChild($panel);
|
||||
return $this->buildStandardPageResponse(
|
||||
$nav,
|
||||
array(
|
||||
'title' => 'Leases',
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
}
|
24
src/applications/drydock/controller/leaselist/__init__.php
Normal file
24
src/applications/drydock/controller/leaselist/__init__.php
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/drydock/constants/leasestatus');
|
||||
phutil_require_module('phabricator', 'applications/drydock/controller/base');
|
||||
phutil_require_module('phabricator', 'applications/drydock/storage/lease');
|
||||
phutil_require_module('phabricator', 'applications/drydock/storage/resource');
|
||||
phutil_require_module('phabricator', 'applications/phid/handle/data');
|
||||
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_module('phutil', 'parser/uri');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('DrydockLeaseListController.php');
|
|
@ -0,0 +1,135 @@
|
|||
<?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 DrydockResourceAllocateController extends DrydockController {
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$resource = new DrydockResource();
|
||||
|
||||
$json = new PhutilJSON();
|
||||
|
||||
$err_attributes = true;
|
||||
$err_capabilities = true;
|
||||
|
||||
$json_attributes = $json->encodeFormatted($resource->getAttributes());
|
||||
$json_capabilities = $json->encodeFormatted($resource->getCapabilities());
|
||||
|
||||
$errors = array();
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$raw_attributes = $request->getStr('attributes');
|
||||
$attributes = json_decode($raw_attributes, true);
|
||||
if (!is_array($attributes)) {
|
||||
$err_attributes = 'Invalid';
|
||||
$errors[] = 'Enter attributes as a valid JSON object.';
|
||||
$json_attributes = $raw_attributes;
|
||||
} else {
|
||||
$resource->setAttributes($attributes);
|
||||
$json_attributes = $json->encodeFormatted($attributes);
|
||||
$err_attributes = null;
|
||||
}
|
||||
|
||||
$raw_capabilities = $request->getStr('capabilities');
|
||||
$capabilities = json_decode($raw_capabilities, true);
|
||||
if (!is_array($capabilities)) {
|
||||
$err_capabilities = 'Invalid';
|
||||
$errors[] = 'Enter capabilities as a valid JSON object.';
|
||||
$json_capabilities = $raw_capabilities;
|
||||
} else {
|
||||
$resource->setCapabilities($capabilities);
|
||||
$json_capabilities = $json->encodeFormatted($capabilities);
|
||||
$err_capabilities = null;
|
||||
}
|
||||
|
||||
$resource->setBlueprintClass($request->getStr('blueprint'));
|
||||
$resource->setType($resource->getBlueprint()->getType());
|
||||
$resource->setOwnerPHID($user->getPHID());
|
||||
$resource->setName($request->getStr('name'));
|
||||
|
||||
if (!$errors) {
|
||||
$resource->save();
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI('/drydock/resource/');
|
||||
}
|
||||
}
|
||||
|
||||
$error_view = null;
|
||||
if ($errors) {
|
||||
$error_view = new AphrontErrorView();
|
||||
$error_view->setTitle('Form Errors');
|
||||
$error_view->setErrors($errors);
|
||||
}
|
||||
|
||||
|
||||
$blueprints = id(new PhutilSymbolLoader())
|
||||
->setType('class')
|
||||
->setAncestorClass('DrydockBlueprint')
|
||||
->selectAndLoadSymbols();
|
||||
$blueprints = ipull($blueprints, 'name', 'name');
|
||||
$panel = new AphrontPanelView();
|
||||
$panel->setWidth(AphrontPanelView::WIDTH_FORM);
|
||||
$panel->setHeader('Allocate Drydock Resource');
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($request->getUser())
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setLabel('Name')
|
||||
->setName('name')
|
||||
->setValue($resource->getName()))
|
||||
->appendChild(
|
||||
id(new AphrontFormSelectControl())
|
||||
->setLabel('Blueprint')
|
||||
->setOptions($blueprints)
|
||||
->setName('blueprint')
|
||||
->setValue($resource->getBlueprintClass()))
|
||||
->appendChild(
|
||||
id(new AphrontFormTextAreaControl())
|
||||
->setLabel('Attributes')
|
||||
->setName('attributes')
|
||||
->setValue($json_attributes)
|
||||
->setError($err_attributes)
|
||||
->setCaption('Specify attributes in JSON.'))
|
||||
->appendChild(
|
||||
id(new AphrontFormTextAreaControl())
|
||||
->setLabel('Capabilities')
|
||||
->setName('capabilities')
|
||||
->setValue($json_capabilities)
|
||||
->setError($err_capabilities)
|
||||
->setCaption('Specify capabilities in JSON.'))
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue('Allocate Resource'));
|
||||
|
||||
$panel->appendChild($form);
|
||||
|
||||
return $this->buildStandardPageResponse(
|
||||
array(
|
||||
$error_view,
|
||||
$panel,
|
||||
),
|
||||
array(
|
||||
'title' => 'Allocate Resource',
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'aphront/response/redirect');
|
||||
phutil_require_module('phabricator', 'applications/drydock/controller/base');
|
||||
phutil_require_module('phabricator', 'applications/drydock/storage/resource');
|
||||
phutil_require_module('phabricator', 'view/form/base');
|
||||
phutil_require_module('phabricator', 'view/form/control/select');
|
||||
phutil_require_module('phabricator', 'view/form/control/submit');
|
||||
phutil_require_module('phabricator', 'view/form/control/text');
|
||||
phutil_require_module('phabricator', 'view/form/control/textarea');
|
||||
phutil_require_module('phabricator', 'view/form/error');
|
||||
phutil_require_module('phabricator', 'view/layout/panel');
|
||||
|
||||
phutil_require_module('phutil', 'parser/json');
|
||||
phutil_require_module('phutil', 'symbols');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('DrydockResourceAllocateController.php');
|
|
@ -0,0 +1,98 @@
|
|||
<?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 DrydockResourceListController extends DrydockController {
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$nav = $this->buildSideNav('resourcelist');
|
||||
|
||||
$pager = new AphrontPagerView();
|
||||
$pager->setURI(new PhutilURI('/drydock/resource/'), 'page');
|
||||
|
||||
$data = id(new DrydockResource())->loadAllWhere(
|
||||
'1 = 1 ORDER BY id DESC LIMIT %d, %d',
|
||||
$pager->getOffset(),
|
||||
$pager->getPageSize() + 1);
|
||||
$data = $pager->sliceResults($data);
|
||||
|
||||
$phids = mpull($data, 'getOwnerPHID');
|
||||
$handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
|
||||
|
||||
$rows = array();
|
||||
foreach ($data as $resource) {
|
||||
$rows[] = array(
|
||||
$resource->getID(),
|
||||
($resource->getOwnerPHID()
|
||||
? $handles[$resource->getOwnerPHID()]->renderLink()
|
||||
: null),
|
||||
phutil_escape_html($resource->getType()),
|
||||
DrydockResourceStatus::getNameForStatus($resource->getStatus()),
|
||||
phutil_escape_html(nonempty($resource->getName(), 'Unnamed')),
|
||||
phabricator_datetime($resource->getDateCreated(), $user),
|
||||
);
|
||||
}
|
||||
|
||||
$table = new AphrontTableView($rows);
|
||||
$table->setHeaders(
|
||||
array(
|
||||
'ID',
|
||||
'Owner',
|
||||
'Type',
|
||||
'Status',
|
||||
'Resource',
|
||||
'Created',
|
||||
));
|
||||
$table->setColumnClasses(
|
||||
array(
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'pri wide',
|
||||
'right',
|
||||
));
|
||||
|
||||
$panel = new AphrontPanelView();
|
||||
$panel->setHeader('Drydock Resources');
|
||||
|
||||
$panel->addButton(
|
||||
phutil_render_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '/drydock/resource/allocate/',
|
||||
'class' => 'green button',
|
||||
),
|
||||
'Allocate Resource'));
|
||||
|
||||
$panel->appendChild($table);
|
||||
$panel->appendChild($pager);
|
||||
|
||||
$nav->appendChild($panel);
|
||||
|
||||
return $this->buildStandardPageResponse(
|
||||
$nav,
|
||||
array(
|
||||
'title' => 'Resources',
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/drydock/constants/resourcestatus');
|
||||
phutil_require_module('phabricator', 'applications/drydock/controller/base');
|
||||
phutil_require_module('phabricator', 'applications/drydock/storage/resource');
|
||||
phutil_require_module('phabricator', 'applications/phid/handle/data');
|
||||
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_module('phutil', 'parser/uri');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('DrydockResourceListController.php');
|
34
src/applications/drydock/interface/base/DrydockInterface.php
Normal file
34
src/applications/drydock/interface/base/DrydockInterface.php
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?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 DrydockInterface {
|
||||
|
||||
private $config;
|
||||
|
||||
abstract public function getInterfaceType();
|
||||
|
||||
final public function setConfiguration(array $config) {
|
||||
$this->config = $config;
|
||||
return $this;
|
||||
}
|
||||
|
||||
final protected function getConfig($key, $default = null) {
|
||||
return idx($this->config, $key, $default);
|
||||
}
|
||||
|
||||
}
|
12
src/applications/drydock/interface/base/__init__.php
Normal file
12
src/applications/drydock/interface/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('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('DrydockInterface.php');
|
|
@ -0,0 +1,43 @@
|
|||
<?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 DrydockCommandInterface extends DrydockInterface {
|
||||
|
||||
final public function getInterfaceType() {
|
||||
return 'command';
|
||||
}
|
||||
|
||||
final public function exec($command) {
|
||||
$argv = func_get_args();
|
||||
$exec = call_user_func_array(
|
||||
array($this, 'getExecFuture'),
|
||||
$argv);
|
||||
return $exec->resolve();
|
||||
}
|
||||
|
||||
final public function execx($command) {
|
||||
$argv = func_get_args();
|
||||
$exec = call_user_func_array(
|
||||
array($this, 'getExecFuture'),
|
||||
$argv);
|
||||
return $exec->resolvex();
|
||||
}
|
||||
|
||||
abstract public function getExecFuture($command);
|
||||
|
||||
}
|
12
src/applications/drydock/interface/command/base/__init__.php
Normal file
12
src/applications/drydock/interface/command/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('DrydockCommandInterface.php');
|
|
@ -0,0 +1,26 @@
|
|||
<?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 DrydockLocalCommandInterface extends DrydockCommandInterface {
|
||||
|
||||
public function getExecFuture($command) {
|
||||
$argv = func_get_args();
|
||||
return newv('ExecFuture', $argv);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/drydock/interface/command/base');
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('DrydockLocalCommandInterface.php');
|
|
@ -0,0 +1,33 @@
|
|||
<?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 DrydockSSHCommandInterface extends DrydockCommandInterface {
|
||||
|
||||
public function getExecFuture($command) {
|
||||
$argv = func_get_args();
|
||||
$full_command = call_user_func_array('csprintf', $argv);
|
||||
|
||||
return new ExecFuture(
|
||||
'ssh -o StrictHostKeyChecking=no -i %s %s@%s -- %s',
|
||||
$this->getConfig('ssh-keyfile'),
|
||||
$this->getConfig('user'),
|
||||
$this->getConfig('host'),
|
||||
$full_command);
|
||||
}
|
||||
|
||||
}
|
15
src/applications/drydock/interface/command/ssh/__init__.php
Normal file
15
src/applications/drydock/interface/command/ssh/__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/interface/command/base');
|
||||
|
||||
phutil_require_module('phutil', 'future/exec');
|
||||
phutil_require_module('phutil', 'xsprintf/csprintf');
|
||||
|
||||
|
||||
phutil_require_source('DrydockSSHCommandInterface.php');
|
25
src/applications/drydock/storage/base/DrydockDAO.php
Normal file
25
src/applications/drydock/storage/base/DrydockDAO.php
Normal file
|
@ -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.
|
||||
*/
|
||||
|
||||
class DrydockDAO extends PhabricatorLiskDAO {
|
||||
|
||||
public function getApplicationName() {
|
||||
return 'drydock';
|
||||
}
|
||||
|
||||
}
|
12
src/applications/drydock/storage/base/__init__.php
Normal file
12
src/applications/drydock/storage/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/base/storage/lisk');
|
||||
|
||||
|
||||
phutil_require_source('DrydockDAO.php');
|
89
src/applications/drydock/storage/lease/DrydockLease.php
Normal file
89
src/applications/drydock/storage/lease/DrydockLease.php
Normal file
|
@ -0,0 +1,89 @@
|
|||
<?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.
|
||||
*/
|
||||
|
||||
class DrydockLease extends DrydockDAO {
|
||||
|
||||
protected $phid;
|
||||
protected $resourceID;
|
||||
protected $until;
|
||||
protected $ownerPHID;
|
||||
protected $attributes = array();
|
||||
protected $status;
|
||||
|
||||
private $resource;
|
||||
|
||||
public function getConfiguration() {
|
||||
return array(
|
||||
self::CONFIG_AUX_PHID => true,
|
||||
self::CONFIG_SERIALIZATION => array(
|
||||
'attributes' => self::SERIALIZATION_JSON,
|
||||
),
|
||||
) + parent::getConfiguration();
|
||||
}
|
||||
|
||||
public function generatePHID() {
|
||||
return PhabricatorPHID::generateNewPHID(
|
||||
PhabricatorPHIDConstants::PHID_TYPE_DRYL);
|
||||
}
|
||||
|
||||
public function getInterface($type) {
|
||||
return $this->getResource()->getInterface($this, $type);
|
||||
}
|
||||
|
||||
public function getResource() {
|
||||
$this->assertActive();
|
||||
if ($this->resource === null) {
|
||||
throw new Exception("Resource is not yet loaded.");
|
||||
}
|
||||
return $this->resource;
|
||||
}
|
||||
|
||||
public function attachResource(DrydockResource $resource) {
|
||||
$this->assertActive();
|
||||
$this->resource = $resource;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function loadResource() {
|
||||
$this->assertActive();
|
||||
return id(new DrydockResource())->loadOneWhere(
|
||||
'id = %d',
|
||||
$this->getResourceID());
|
||||
}
|
||||
|
||||
public function release() {
|
||||
|
||||
// TODO: Insert a cleanup task into the taskmaster queue.
|
||||
|
||||
$this->setStatus(DrydockLeaseStatus::STATUS_RELEASED);
|
||||
$this->save();
|
||||
|
||||
$this->resource = null;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function assertActive() {
|
||||
if ($this->status != DrydockLeaseStatus::STATUS_ACTIVE) {
|
||||
throw new Exception(
|
||||
"Lease is not active! You can not interact with resources through ".
|
||||
"an inactive lease.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
18
src/applications/drydock/storage/lease/__init__.php
Normal file
18
src/applications/drydock/storage/lease/__init__.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/drydock/constants/leasestatus');
|
||||
phutil_require_module('phabricator', 'applications/drydock/storage/base');
|
||||
phutil_require_module('phabricator', 'applications/drydock/storage/resource');
|
||||
phutil_require_module('phabricator', 'applications/phid/constants');
|
||||
phutil_require_module('phabricator', 'applications/phid/storage/phid');
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('DrydockLease.php');
|
|
@ -0,0 +1,69 @@
|
|||
<?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.
|
||||
*/
|
||||
|
||||
class DrydockResource extends DrydockDAO {
|
||||
|
||||
protected $id;
|
||||
protected $phid;
|
||||
protected $blueprintClass;
|
||||
protected $status;
|
||||
|
||||
protected $type;
|
||||
protected $name;
|
||||
protected $attributes = array();
|
||||
protected $capabilities = array();
|
||||
protected $ownerPHID;
|
||||
|
||||
|
||||
private $blueprint;
|
||||
|
||||
public function getConfiguration() {
|
||||
return array(
|
||||
self::CONFIG_AUX_PHID => true,
|
||||
self::CONFIG_SERIALIZATION => array(
|
||||
'attributes' => self::SERIALIZATION_JSON,
|
||||
'capabilities' => self::SERIALIZATION_JSON,
|
||||
),
|
||||
) + parent::getConfiguration();
|
||||
}
|
||||
|
||||
public function generatePHID() {
|
||||
return PhabricatorPHID::generateNewPHID(
|
||||
PhabricatorPHIDConstants::PHID_TYPE_DRYR);
|
||||
}
|
||||
|
||||
public function getAttribute($key, $default = null) {
|
||||
return idx($this->attributes, $key, $default);
|
||||
}
|
||||
|
||||
public function getCapability($key, $default = null) {
|
||||
return idx($this->capbilities, $key, $default);
|
||||
}
|
||||
|
||||
public function getInterface(DrydockLease $lease, $type) {
|
||||
return $this->getBlueprint()->getInterface($this, $lease, $type);
|
||||
}
|
||||
|
||||
public function getBlueprint() {
|
||||
if (empty($this->blueprint)) {
|
||||
$this->blueprint = newv($this->blueprintClass, array());
|
||||
}
|
||||
return $this->blueprint;
|
||||
}
|
||||
|
||||
}
|
16
src/applications/drydock/storage/resource/__init__.php
Normal file
16
src/applications/drydock/storage/resource/__init__.php
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/drydock/storage/base');
|
||||
phutil_require_module('phabricator', 'applications/phid/constants');
|
||||
phutil_require_module('phabricator', 'applications/phid/storage/phid');
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('DrydockResource.php');
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
* 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.
|
||||
|
@ -34,6 +34,8 @@ final class PhabricatorPHIDConstants {
|
|||
const PHID_TYPE_POLL = 'POLL';
|
||||
const PHID_TYPE_WIKI = 'WIKI';
|
||||
const PHID_TYPE_APRJ = 'APRJ';
|
||||
const PHID_TYPE_ACMT = 'ACMT';
|
||||
const PHID_TYPE_ACMT = 'ACMT';
|
||||
const PHID_TYPE_DRYR = 'DRYR';
|
||||
const PHID_TYPE_DRYL = 'DRYL';
|
||||
|
||||
}
|
||||
|
|
8
src/docs/userguide/drydock.diviner
Normal file
8
src/docs/userguide/drydock.diviner
Normal file
|
@ -0,0 +1,8 @@
|
|||
@title Drydock User Guide
|
||||
@group userguide
|
||||
|
||||
Configuring Drydock for machine resource management.
|
||||
|
||||
= Overview =
|
||||
|
||||
NOTE: Drydock is extremely new and not very useful yet.
|
Loading…
Reference in a new issue