get deployment plan
This commit is contained in:
@@ -5,6 +5,7 @@ namespace App\Drivers\Caddy;
|
|||||||
use App\Drivers\GatewayDriver;
|
use App\Drivers\GatewayDriver;
|
||||||
use App\Data\Deployments\Plan;
|
use App\Data\Deployments\Plan;
|
||||||
use App\Data\Deployments\PlannedStep as Step;
|
use App\Data\Deployments\PlannedStep as Step;
|
||||||
|
use App\Enums\DeploymentStatus;
|
||||||
use App\Models\Service;
|
use App\Models\Service;
|
||||||
|
|
||||||
class Caddy2Driver extends GatewayDriver
|
class Caddy2Driver extends GatewayDriver
|
||||||
@@ -20,8 +21,15 @@ class Caddy2Driver extends GatewayDriver
|
|||||||
$this->containerName = $containerName;
|
$this->containerName = $containerName;
|
||||||
$this->containerId = $containerId;
|
$this->containerId = $containerId;
|
||||||
$this->service = $service;
|
$this->service = $service;
|
||||||
|
}
|
||||||
|
|
||||||
$this->deploymentPlan = new Plan(steps: [
|
public function getDeploymentPlan(string $deploymentHash): Plan
|
||||||
|
{
|
||||||
|
$previousDeployment = $this->service?->deployments()
|
||||||
|
->where('status', DeploymentStatus::COMPLETED)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
return new Plan(steps: [
|
||||||
new Step(
|
new Step(
|
||||||
name: 'Generate Caddyfile',
|
name: 'Generate Caddyfile',
|
||||||
script: function () {
|
script: function () {
|
||||||
@@ -36,23 +44,23 @@ class Caddy2Driver extends GatewayDriver
|
|||||||
),
|
),
|
||||||
new Step(
|
new Step(
|
||||||
name: 'Run the docker image',
|
name: 'Run the docker image',
|
||||||
script: function () {
|
script: function () use ($previousDeployment, $deploymentHash) {
|
||||||
$script = collect();
|
$script = collect();
|
||||||
if ($this->containerName) {
|
if ($this->containerName && $previousDeployment) {
|
||||||
$script->push('docker stop '.$this->containerName.' || true');
|
$script->push("docker stop \"{$this->containerName}-{$previousDeployment->hash}\" || true");
|
||||||
} elseif ($this->containerId) {
|
} elseif ($this->containerId) {
|
||||||
$script->push('docker stop '.$this->containerId.' || true');
|
$script->push('docker stop ' . $this->containerId . ' || true');
|
||||||
}
|
}
|
||||||
|
|
||||||
$runCommand = 'docker run -d';
|
$runCommand = 'docker run -d';
|
||||||
if ($this->containerName) {
|
if ($this->containerName) {
|
||||||
$runCommand .= " --name {$this->containerName}";
|
$runCommand .= " --name \"{$this->containerName}-{$deploymentHash}\"";
|
||||||
}
|
}
|
||||||
$runCommand .= ' -p 80:80 -p 443:443 caddy:2';
|
$runCommand .= ' -p 80:80 -p 443:443 caddy:2';
|
||||||
|
|
||||||
$script->push($runCommand);
|
$script->push($runCommand);
|
||||||
|
|
||||||
return $script->join("\n");
|
return $script->join(" && ");
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ abstract class Driver
|
|||||||
{
|
{
|
||||||
public ?Service $service;
|
public ?Service $service;
|
||||||
|
|
||||||
public Plan $deploymentPlan;
|
|
||||||
|
|
||||||
public ?string $containerName;
|
public ?string $containerName;
|
||||||
|
|
||||||
public ?string $containerId;
|
public ?string $containerId;
|
||||||
@@ -20,4 +18,6 @@ abstract class Driver
|
|||||||
?string $containerId = null,
|
?string $containerId = null,
|
||||||
?Service $service = null,
|
?Service $service = null,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
abstract public function getDeploymentPlan(string $deploymentHash): Plan;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ namespace App\Drivers\Postgres;
|
|||||||
use App\Data\Deployments\Plan;
|
use App\Data\Deployments\Plan;
|
||||||
use App\Data\Deployments\PlannedStep as Step;
|
use App\Data\Deployments\PlannedStep as Step;
|
||||||
use App\Drivers\DatabaseDriver;
|
use App\Drivers\DatabaseDriver;
|
||||||
|
use App\Enums\DeploymentStatus;
|
||||||
use App\Models\Service;
|
use App\Models\Service;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
@@ -19,27 +20,40 @@ class Postgres17Driver extends DatabaseDriver
|
|||||||
public ?array $credentials = null,
|
public ?array $credentials = null,
|
||||||
) {
|
) {
|
||||||
$credentials = $credentials ?? $this->defaultCredentials();
|
$credentials = $credentials ?? $this->defaultCredentials();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDeploymentPlan(string $deploymentHash): Plan
|
||||||
|
{
|
||||||
$user = $credentials['user'] ?? null;
|
$user = $credentials['user'] ?? null;
|
||||||
$password = $credentials['password'] ?? null;
|
$password = $credentials['password'] ?? null;
|
||||||
$db = $credentials['db'] ?? null;
|
$db = $credentials['db'] ?? null;
|
||||||
|
|
||||||
$this->deploymentPlan = new Plan(steps: [
|
if (!$user || !$password || !$db) {
|
||||||
|
throw new \InvalidArgumentException('Missing required credentials');
|
||||||
|
}
|
||||||
|
|
||||||
|
$previousDeployment = $this->service?->deployments()
|
||||||
|
->where('status', DeploymentStatus::COMPLETED)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
return new Plan(steps: [
|
||||||
new Step(
|
new Step(
|
||||||
name: 'Run the docker image',
|
name: 'Run the docker image',
|
||||||
secrets: [
|
secrets: [
|
||||||
'password' => $password
|
'password' => $password
|
||||||
],
|
],
|
||||||
script: function () use ($user, $password, $db) {
|
script: function () use ($user, $password, $db, $previousDeployment, $deploymentHash) {
|
||||||
$script = collect();
|
$script = collect();
|
||||||
if ($this->containerName) {
|
|
||||||
$script->push('docker stop '.$this->containerName.' || true');
|
if ($this->containerName && $previousDeployment) {
|
||||||
|
$script->push("docker stop \"{$this->containerName}-{$previousDeployment->hash}\" || true");
|
||||||
} elseif ($this->containerId) {
|
} elseif ($this->containerId) {
|
||||||
$script->push('docker stop '.$this->containerId.' || true');
|
$script->push('docker stop ' . $this->containerId . ' || true');
|
||||||
}
|
}
|
||||||
|
|
||||||
$runCommand = 'docker run -d';
|
$runCommand = 'docker run -d';
|
||||||
if ($this->containerName) {
|
if ($this->containerName) {
|
||||||
$runCommand .= " --name {$this->containerName}";
|
$runCommand .= " --name \"{$this->containerName}-{$deploymentHash}\"";
|
||||||
}
|
}
|
||||||
if ($password) {
|
if ($password) {
|
||||||
$runCommand .= ' -e POSTGRES_PASSWORD=[!password!]';
|
$runCommand .= ' -e POSTGRES_PASSWORD=[!password!]';
|
||||||
@@ -54,7 +68,7 @@ class Postgres17Driver extends DatabaseDriver
|
|||||||
|
|
||||||
$script->push($runCommand);
|
$script->push($runCommand);
|
||||||
|
|
||||||
return $runCommand;
|
return $script->join(" && ");
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
new Step(
|
new Step(
|
||||||
|
|||||||
@@ -24,13 +24,14 @@ class DeployService implements ShouldQueue
|
|||||||
public function handle(): void
|
public function handle(): void
|
||||||
{
|
{
|
||||||
$driver = $this->service->driver();
|
$driver = $this->service->driver();
|
||||||
|
$deploymentPlan = $driver->getDeploymentPlan($this->deployment->hash);
|
||||||
$this->service->update([
|
$this->service->update([
|
||||||
'status' => ServiceStatus::INSTALLING,
|
'status' => ServiceStatus::INSTALLING,
|
||||||
]);
|
]);
|
||||||
$this->deployment = $this->service->deployments()->create([
|
$this->deployment = $this->service->deployments()->create([
|
||||||
'status' => DeploymentStatus::PENDING,
|
'status' => DeploymentStatus::PENDING,
|
||||||
]);
|
]);
|
||||||
foreach ($driver->deploymentPlan->steps as $index => $plannedStep) {
|
foreach ($deploymentPlan->steps as $index => $plannedStep) {
|
||||||
$step = $this->deployment->steps()->create([
|
$step = $this->deployment->steps()->create([
|
||||||
'order' => $index + 1,
|
'order' => $index + 1,
|
||||||
'status' => DeploymentStatus::PENDING,
|
'status' => DeploymentStatus::PENDING,
|
||||||
|
|||||||
@@ -10,6 +10,15 @@ class Deployment extends Model
|
|||||||
{
|
{
|
||||||
protected $guarded = [];
|
protected $guarded = [];
|
||||||
|
|
||||||
|
public static function boot(): void
|
||||||
|
{
|
||||||
|
parent::boot();
|
||||||
|
|
||||||
|
static::creating(function (self $deployment) {
|
||||||
|
$deployment->hash = str()->random(16);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
protected function casts(): array
|
protected function casts(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ return new class extends Migration
|
|||||||
{
|
{
|
||||||
Schema::create('deployments', function (Blueprint $table) {
|
Schema::create('deployments', function (Blueprint $table) {
|
||||||
$table->id();
|
$table->id();
|
||||||
|
$table->string('hash')->unique();
|
||||||
$table->morphs('target'); // server, service, etc.
|
$table->morphs('target'); // server, service, etc.
|
||||||
$table->string('status');
|
$table->string('status');
|
||||||
$table->dateTime('started_at')->nullable();
|
$table->dateTime('started_at')->nullable();
|
||||||
|
|||||||
Reference in New Issue
Block a user