Page MenuHomec4science

DrydockEC2HostBlueprint.php
No OneTemporary

File Metadata

Created
Tue, Jul 23, 07:13

DrydockEC2HostBlueprint.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.
*/
final class DrydockEC2HostBlueprint extends DrydockRemoteHostBlueprint {
public function canAllocateResources() {
return true;
}
public function executeAllocateResource() {
$resource = $this->newResourceTemplate('EC2 Host');
$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];
$this->log('Started Instance: {$instance_id}');
$resource->setAttribute('instance.id', $instance_id);
$resource->save();
$n = 1;
do {
$xml = $this->executeEC2Query(
'DescribeInstances',
array(
'InstanceId.1' => $instance_id,
));
$instance = $xml->reservationSet[0]->item[0]->instancesSet[0]->item[0];
$state = (string)$instance->instanceState[0]->name;
if ($state == 'pending') {
sleep(min($n++, 15));
} else if ($state == 'running') {
break;
} else {
$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 {
$xml = $this->executeEC2Query(
'DescribeInstanceStatus',
array(
'InstanceId' => $instance_id,
));
$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 {
$this->log(
"EC2 system and instance status in bad states: ".
"'{$system_status}', '{$instance_status}'.");
$resource->setStatus(DrydockResourceStatus::STATUS_BROKEN);
$resource->save();
}
} while (true);
$resource->setAttributes(
array(
'host' => (string)$instance->dnsName,
'user' => 'ec2-user',
'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();
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();
}
}

Event Timeline