diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -722,6 +722,7 @@ 'DrydockLeaseSearchEngine' => 'applications/drydock/query/DrydockLeaseSearchEngine.php', 'DrydockLeaseStatus' => 'applications/drydock/constants/DrydockLeaseStatus.php', 'DrydockLeaseViewController' => 'applications/drydock/controller/DrydockLeaseViewController.php', + 'DrydockLibvirtHostBlueprintImplementation' => 'applications/drydock/blueprint/DrydockLibvirtHostBlueprintImplementation.php', 'DrydockLocalCommandInterface' => 'applications/drydock/interface/command/DrydockLocalCommandInterface.php', 'DrydockLog' => 'applications/drydock/storage/DrydockLog.php', 'DrydockLogController' => 'applications/drydock/controller/DrydockLogController.php', @@ -3914,6 +3915,7 @@ 'DrydockLeaseSearchEngine' => 'PhabricatorApplicationSearchEngine', 'DrydockLeaseStatus' => 'DrydockConstants', 'DrydockLeaseViewController' => 'DrydockLeaseController', + 'DrydockLibvirtHostBlueprintImplementation' => 'DrydockMinMaxExpiryBlueprintImplementation', 'DrydockLocalCommandInterface' => 'DrydockCommandInterface', 'DrydockLog' => array( 'DrydockDAO', diff --git a/src/applications/drydock/blueprint/DrydockLibvirtHostBlueprintImplementation.php b/src/applications/drydock/blueprint/DrydockLibvirtHostBlueprintImplementation.php new file mode 100644 --- /dev/null +++ b/src/applications/drydock/blueprint/DrydockLibvirtHostBlueprintImplementation.php @@ -0,0 +1,773 @@ +getAttribute('platform') === $this->getDetail('platform'); + $custom_match = DrydockCustomAttributes::hasRequirements( + $lease->getAttributes(), + $this->getDetail('attributes')); + + if ($platform_match && $custom_match) { + $this->log(pht( + 'This blueprint can allocate a resource for the specified lease.')); + } else { + $this->log(pht( + 'This blueprint can not allocate a resource for the specified lease.')); + } + + return $platform_match && $custom_match; + } + + protected function canAllocateLease( + DrydockResource $resource, + DrydockLease $lease) { + + $platform_match = + $lease->getAttribute('platform') === $resource->getAttribute('platform'); + $custom_match = DrydockCustomAttributes::hasRequirements( + $lease->getAttributes(), + $this->getDetail('attributes')); + + if ($platform_match && $custom_match) { + $this->log(pht( + 'This blueprint can allocate the specified lease.')); + } else { + $this->log(pht( + 'This blueprint can not allocate the specified lease.')); + } + + return $platform_match && $custom_match; + } + + protected function executeInitializePendingResource( + DrydockResource $resource, + DrydockLease $lease) { + + // We must set the platform so that other allocators will lease + // against it successfully. + $resource + ->setAttribute( + 'platform', + $this->getDetail('platform')) + ->save(); + } + + private function getSSHFuture($credential, $command) { + $argv = func_get_args(); + array_shift($argv); + $future = new ExecFuture( + 'ssh '. + '-o LogLevel=quiet '. + '-o StrictHostKeyChecking=no '. + '-o UserKnownHostsFile=/dev/null '. + '-o BatchMode=yes '. + '-p %s -i %P %P@%s -- %s', + $this->getDetail('port'), + $credential->getKeyfileEnvelope(), + $credential->getUsernameEnvelope(), + $this->getDetail('host'), + call_user_func_array('csprintf', $argv)); + return $future; + } + + protected function executeAllocateResource( + DrydockResource $resource, + DrydockLease $lease) { + + $credential = id(new PassphraseCredentialQuery()) + ->setViewer(PhabricatorUser::getOmnipotentUser()) + ->withPHIDs(array($this->getDetail('keypair'))) + ->executeOne(); + + if ($credential === null) { + throw new Exception('Specified credential does not exist!'); + } + + $this->log(pht( + 'Using credential %d to allocate.', + $credential->getID())); + + $loaded_credential = PassphraseSSHKey::loadFromPHID( + $this->getDetail('keypair'), + PhabricatorUser::getOmnipotentUser()); + + $winrm_auth_id = null; + if ($this->getDetail('platform') === 'windows') { + $winrm_auth = id(new PassphraseCredentialQuery()) + ->setViewer(PhabricatorUser::getOmnipotentUser()) + ->withPHIDs(array($this->getDetail('winrm-auth'))) + ->executeOne(); + + if ($winrm_auth === null) { + throw new Exception( + 'Specified credential for WinRM auth does not exist!'); + } + + $winrm_auth_id = $winrm_auth->getID(); + + $this->log(pht( + 'Using credential %d to authenticate over WinRM.', + $winrm_auth_id)); + } + + $pool_name = $this->getDetail('storage-pool'); + $image_name = 'image-'.$resource->getID(); + $vm_name = 'vm-'.$resource->getID(); + + $this->log(pht( + 'Allocating new image from "%s" as "%s".', + $this->getDetail('base-image'), + $image_name)); + + $future = $this->getSSHFuture( + $loaded_credential, + '/usr/bin/virsh vol-create-as %s %s 256GB '. + '--format qcow2 --backing-vol %s '. + '--backing-vol-format qcow2', + $this->getDetail('storage-pool'), + $image_name, + $this->getDetail('base-image')); + $future->resolvex(); + + $this->log(pht( + 'Allocated new image from "%s" as "%s".', + $this->getDetail('base-image'), + $image_name)); + + $this->log(pht( + 'Retrieving path to new image "%s".', + $image_name)); + + $future = $this->getSSHFuture( + $loaded_credential, + '/usr/bin/virsh vol-path %s --pool %s', + $image_name, + $this->getDetail('storage-pool')); + list($stdout, $stderr) = $future->resolvex(); + $image_path = trim($stdout); + + $this->log(pht( + 'Retrieved image path of "%s" as "%s".', + $image_name, + $image_path)); + + $ram = $this->getDetail('ram'); + $vcpu = $this->getDetail('cpu'); + $network = $this->getDetail('network-id'); + + $xml = << + $vm_name + $ram + $ram + $vcpu + + hvm + + + + + + + + + Nehalem + + + + + + + destroy + restart + restart + + /usr/bin/qemu-system-x86_64 + + + + +
+ + +
+ + + +
+ + + +
+ + + +
+ + +
+ + +
+ + + + +
+ + + + + + + + + +
+ + + + + + + +
+ +