Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
189 changes: 189 additions & 0 deletions app/Services/DigitalOcean/DigitalOceanAccountService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
<?php

declare(strict_types=1);

namespace Bigpixelrocket\DeployerPHP\Services\DigitalOcean;

use DigitalOceanV2\Client;
use DigitalOceanV2\Entity\Image as ImageEntity;
use DigitalOceanV2\Entity\Region as RegionEntity;
use DigitalOceanV2\Entity\Size as SizeEntity;

/**
* DigitalOcean account data service.
*
* Handles fetching account-level resources: regions, sizes, images, VPCs, SSH keys.
*/
class DigitalOceanAccountService
{
private ?Client $api = null;

/**
* Set the DigitalOcean API client.
*/
public function setAPI(Client $api): void
{
$this->api = $api;
}

/**
* Get available DigitalOcean regions.
*
* @return array<string, string> Array of region slug => description
*/
public function getAvailableRegions(): array
{
$client = $this->getAPI();

try {
$regionApi = $client->region();
$regions = $regionApi->getAll();

$options = [];
foreach ($regions as $region) {
/** @var RegionEntity $region */
if ($region->available) {
$options[$region->slug] = "{$region->name} ({$region->slug})";
}
}

return $options;
} catch (\Throwable $e) {
throw new \RuntimeException('Failed to fetch regions: ' . $e->getMessage(), 0, $e);
}
}

/**
* Get available droplet sizes.
*
* @return array<string, string> Array of size slug => description
*/
public function getAvailableSizes(): array
{
$client = $this->getAPI();

try {
$sizeApi = $client->size();
$sizes = $sizeApi->getAll();

$options = [];
foreach ($sizes as $size) {
/** @var SizeEntity $size */
if ($size->available) {
$vcpus = $size->vcpus;
$memory = $size->memory / 1024; // Convert MB to GB
$disk = $size->disk;
$price = $size->priceMonthly;

$options[$size->slug] = "{$size->slug} - {$vcpus} vCPU, {$memory}GB RAM, {$disk}GB SSD (\${$price}/mo)";
}
}

return $options;
} catch (\Throwable $e) {
throw new \RuntimeException('Failed to fetch sizes: ' . $e->getMessage(), 0, $e);
}
}

/**
* Get available OS images (filtered to Ubuntu and Debian only).
*
* @return array<string, string> Array of image slug => description
*/
public function getAvailableImages(): array
{
$client = $this->getAPI();

try {
$imageApi = $client->image();

// Get distribution images (not snapshots or backups)
$images = $imageApi->getAll(['type' => 'distribution']);

$options = [];
foreach ($images as $image) {
/** @var ImageEntity $image */
// Filter to only Ubuntu and Debian distributions
if ($image->status === 'available' && $image->public === true) {
$distribution = strtolower($image->distribution ?? '');

if (in_array($distribution, ['ubuntu', 'debian'], true)) {
$slug = $image->slug;
if ($slug !== null && $slug !== '') {
$options[$slug] = "{$image->distribution} {$image->name}";
}
}
}
}

return $options;
} catch (\Throwable $e) {
throw new \RuntimeException('Failed to fetch images: ' . $e->getMessage(), 0, $e);
}
}

/**
* Get user's VPCs for a specific region.
*
* @return array<string, string> Array of VPC UUID => name
*/
public function getUserVpcs(string $region): array
{
$client = $this->getAPI();

try {
$vpcApi = $client->vpc();
$vpcs = $vpcApi->getAll();

$options = ['default' => 'Use default VPC'];
foreach ($vpcs as $vpc) {
if ($vpc->region === $region) {
$options[$vpc->id] = "{$vpc->name} ({$vpc->id})";
}
}

return $options;
} catch (\Throwable $e) {
throw new \RuntimeException('Failed to fetch VPCs: ' . $e->getMessage(), 0, $e);
}
}

/**
* Get user's SSH keys.
*
* @return array<int, string> Array of key ID => description
*/
public function getUserSshKeys(): array
{
$client = $this->getAPI();

try {
$keyApi = $client->key();
$keys = $keyApi->getAll();

$options = [];
foreach ($keys as $key) {
$fingerprint = substr($key->fingerprint, 0, 16) . '...';
$options[$key->id] = "{$key->name} ({$fingerprint})";
}

return $options;
} catch (\Throwable $e) {
throw new \RuntimeException('Failed to fetch SSH keys: ' . $e->getMessage(), 0, $e);
}
}

/**
* Get the configured DigitalOcean API client.
*
* @throws \RuntimeException If client not configured
*/
private function getAPI(): Client
{
if ($this->api === null) {
throw new \RuntimeException('DigitalOcean API client not configured. Call setAPI() first.');
}

return $this->api;
}
}
Loading
Loading