diff --git a/.env.example b/.env.example index 952d224e9..dd4f03d08 100644 --- a/.env.example +++ b/.env.example @@ -13,6 +13,7 @@ APP_ENV=local APP_KEY= APP_DEBUG=true APP_URL=http://localhost +APP_PORT=8000 DB_CONNECTION=pgsql DB_HOST=postgres diff --git a/app/Actions/RemoteProcess/RunRemoteProcess.php b/app/Actions/RemoteProcess/RunRemoteProcess.php index 731eea533..da2eeb8bc 100644 --- a/app/Actions/RemoteProcess/RunRemoteProcess.php +++ b/app/Actions/RemoteProcess/RunRemoteProcess.php @@ -7,6 +7,7 @@ use App\Enums\ProcessStatus; use Illuminate\Process\ProcessResult; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Process; +use Illuminate\Support\Facades\Storage; use Spatie\Activitylog\Models\Activity; class RunRemoteProcess @@ -69,13 +70,15 @@ class RunRemoteProcess $command = $this->activity->getExtraProperty('command'); $delimiter = 'EOF-COOLIFY-SSH'; + Storage::disk('local')->makeDirectory('.ssh'); $ssh_command = "ssh " . "-i {$private_key_location} " . '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ' . '-o PasswordAuthentication=no ' . '-o RequestTTY=no ' - . "-o LogLevel=ERROR " + . '-o LogLevel=ERROR ' + . '-o ControlMaster=auto -o ControlPersist=yes -o ControlPersist=1m -o ControlPath=/var/www/html/storage/app/.ssh/ssh_mux_%h_%p_%r ' . "-p {$port} " . "{$user}@{$destination} " . " 'bash -se' << \\$delimiter" . PHP_EOL diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php new file mode 100644 index 000000000..f3e987682 --- /dev/null +++ b/app/Http/Controllers/HomeController.php @@ -0,0 +1,12 @@ +projects; + return view('home', ['projects' => $projects]); + } +} diff --git a/app/Models/Application.php b/app/Models/Application.php new file mode 100644 index 000000000..875a6c790 --- /dev/null +++ b/app/Models/Application.php @@ -0,0 +1,15 @@ +belongsTo(Environment::class); + } + public function destination() + { + return $this->morphTo(); + } +} diff --git a/app/Models/Database.php b/app/Models/Database.php new file mode 100644 index 000000000..ab0476d27 --- /dev/null +++ b/app/Models/Database.php @@ -0,0 +1,15 @@ +belongsTo(Environment::class); + } + public function destination() + { + return $this->morphTo(); + } +} diff --git a/app/Models/Environment.php b/app/Models/Environment.php new file mode 100644 index 000000000..86e784ef2 --- /dev/null +++ b/app/Models/Environment.php @@ -0,0 +1,20 @@ +hasMany(Application::class); + } + public function databases() + { + return $this->hasMany(Database::class); + } + public function services() + { + return $this->hasMany(Service::class); + } +} + diff --git a/app/Models/Kubernetes.php b/app/Models/Kubernetes.php new file mode 100644 index 000000000..fe2e65ca8 --- /dev/null +++ b/app/Models/Kubernetes.php @@ -0,0 +1,11 @@ +hasMany(PrivateKeyable::class); - } - public function servers() { - return $this->morphedByMany(Server::class, 'private_keyable'); + return $this->hasMany(Server::class); } } diff --git a/app/Models/Project.php b/app/Models/Project.php new file mode 100644 index 000000000..1efe88548 --- /dev/null +++ b/app/Models/Project.php @@ -0,0 +1,13 @@ +hasMany(Environment::class); + } + public function settings() { + return $this->hasOne(ProjectSetting::class); + } +} diff --git a/app/Models/ProjectSetting.php b/app/Models/ProjectSetting.php new file mode 100644 index 000000000..78dcb32ba --- /dev/null +++ b/app/Models/ProjectSetting.php @@ -0,0 +1,7 @@ +morphToMany(PrivateKey::class, 'private_keyable'); + return $this->belongsTo(PrivateKey::class); } } diff --git a/app/Models/Service.php b/app/Models/Service.php new file mode 100644 index 000000000..e3df5dfa7 --- /dev/null +++ b/app/Models/Service.php @@ -0,0 +1,16 @@ +belongsTo(Environment::class); + } + public function destination() + { + return $this->morphTo(); + } +} diff --git a/app/Models/StandaloneDocker.php b/app/Models/StandaloneDocker.php new file mode 100644 index 000000000..5d6f8ef4e --- /dev/null +++ b/app/Models/StandaloneDocker.php @@ -0,0 +1,11 @@ +morphMany(Application::class, 'destination'); + } +} diff --git a/app/Models/SwarmDocker.php b/app/Models/SwarmDocker.php new file mode 100644 index 000000000..6d9a93c40 --- /dev/null +++ b/app/Models/SwarmDocker.php @@ -0,0 +1,11 @@ +morphMany(Application::class, 'destination'); + } +} diff --git a/app/Models/Team.php b/app/Models/Team.php index 90d4d73d9..3b05aa1ee 100644 --- a/app/Models/Team.php +++ b/app/Models/Team.php @@ -10,4 +10,10 @@ class Team extends BaseModel protected $fillable = [ 'name', ]; + public function projects() { + return $this->hasMany(Project::class); + } + public function servers() { + return $this->hasMany(Server::class); + } } diff --git a/bootstrap/helpers.php b/bootstrap/helpers.php index 6f9b04cad..494bb6470 100644 --- a/bootstrap/helpers.php +++ b/bootstrap/helpers.php @@ -20,7 +20,7 @@ if (!function_exists('remoteProcess')) { checkTeam($found_server->team_id); $temp_file = 'id.rsa_'.'root'.'@'.$found_server->ip; - Storage::disk('local')->put($temp_file, $found_server->privateKeys->first()->private_key, 'private'); + Storage::disk('local')->put($temp_file, $found_server->privateKey->private_key, 'private'); $private_key_location = '/var/www/html/storage/app/'.$temp_file; return resolve(DispatchRemoteProcess::class, [ diff --git a/database/migrations/2023_03_24_140711_create_servers_table.php b/database/migrations/2023_03_24_140711_create_servers_table.php index 0cbd2419a..ba62f7977 100644 --- a/database/migrations/2023_03_24_140711_create_servers_table.php +++ b/database/migrations/2023_03_24_140711_create_servers_table.php @@ -20,6 +20,7 @@ return new class extends Migration $table->integer('port')->default(22); $table->string('user')->default('root'); $table->foreignId('team_id'); + $table->foreignId('private_key_id'); $table->timestamps(); }); } diff --git a/database/migrations/2023_03_24_140853_create_private_keys_table.php b/database/migrations/2023_03_24_140853_create_private_keys_table.php index 09c6ab0ee..be0c5211f 100644 --- a/database/migrations/2023_03_24_140853_create_private_keys_table.php +++ b/database/migrations/2023_03_24_140853_create_private_keys_table.php @@ -17,7 +17,6 @@ return new class extends Migration $table->string('name'); $table->string('description')->nullable(); $table->longText('private_key'); - $table->nullableMorphs('private_keys_morph'); $table->timestamps(); }); } diff --git a/database/migrations/2023_03_27_075351_create_projects_table.php b/database/migrations/2023_03_27_075351_create_projects_table.php new file mode 100644 index 000000000..432496268 --- /dev/null +++ b/database/migrations/2023_03_27_075351_create_projects_table.php @@ -0,0 +1,33 @@ +id(); + $table->string('uuid')->unique(); + $table->string('name'); + $table->string('description')->nullable(); + + $table->foreignId('team_id'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('projects'); + } +}; diff --git a/database/migrations/2023_03_24_203356_create_private_keyables_table.php b/database/migrations/2023_03_27_075443_create_project_settings_table.php similarity index 60% rename from database/migrations/2023_03_24_203356_create_private_keyables_table.php rename to database/migrations/2023_03_27_075443_create_project_settings_table.php index 7c110413c..40e8bed1f 100644 --- a/database/migrations/2023_03_24_203356_create_private_keyables_table.php +++ b/database/migrations/2023_03_27_075443_create_project_settings_table.php @@ -11,11 +11,13 @@ return new class extends Migration */ public function up(): void { - Schema::create('private_keyables', function (Blueprint $table) { + Schema::create('project_settings', function (Blueprint $table) { $table->id(); - $table->unsignedBigInteger('private_key_id'); - $table->unsignedBigInteger('private_keyable_id'); - $table->string('private_keyable_type'); + $table->string('uuid')->unique(); + $table->string('wildcard_domain')->nullable(); + + $table->foreignId('project_id'); + $table->timestamps(); }); } @@ -25,6 +27,6 @@ return new class extends Migration */ public function down(): void { - Schema::dropIfExists('private_keyables'); + Schema::dropIfExists('project_settings'); } }; diff --git a/database/migrations/2023_03_27_075444_create_environments_table.php b/database/migrations/2023_03_27_075444_create_environments_table.php new file mode 100644 index 000000000..708621f42 --- /dev/null +++ b/database/migrations/2023_03_27_075444_create_environments_table.php @@ -0,0 +1,30 @@ +id(); + $table->string('uuid')->unique(); + $table->string('name')->unique(); + $table->foreignId('project_id'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('environments'); + } +}; diff --git a/database/migrations/2023_03_27_081716_create_applications_table.php b/database/migrations/2023_03_27_081716_create_applications_table.php new file mode 100644 index 000000000..c5a2570e5 --- /dev/null +++ b/database/migrations/2023_03_27_081716_create_applications_table.php @@ -0,0 +1,33 @@ +id(); + $table->string('uuid')->unique(); + $table->string('name'); + + $table->morphs('destination'); + $table->foreignId('environment_id'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('applications'); + } +}; diff --git a/database/migrations/2023_03_27_083620_create_databases_table.php b/database/migrations/2023_03_27_083620_create_databases_table.php new file mode 100644 index 000000000..9173e4b11 --- /dev/null +++ b/database/migrations/2023_03_27_083620_create_databases_table.php @@ -0,0 +1,33 @@ +id(); + $table->string('uuid')->unique(); + $table->string('name'); + + $table->morphs('destination'); + $table->foreignId('environment_id'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('databases'); + } +}; diff --git a/database/migrations/2023_03_27_083621_create_services_table.php b/database/migrations/2023_03_27_083621_create_services_table.php new file mode 100644 index 000000000..a5c10c0b0 --- /dev/null +++ b/database/migrations/2023_03_27_083621_create_services_table.php @@ -0,0 +1,32 @@ +id(); + $table->string('uuid')->unique(); + $table->string('name'); + + $table->morphs('destination'); + $table->foreignId('environment_id'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('services'); + } +}; diff --git a/database/migrations/2023_03_27_085022_create_standalone_dockers_table.php b/database/migrations/2023_03_27_085022_create_standalone_dockers_table.php new file mode 100644 index 000000000..184d1e3e2 --- /dev/null +++ b/database/migrations/2023_03_27_085022_create_standalone_dockers_table.php @@ -0,0 +1,30 @@ +id(); + $table->string('uuid')->unique(); + + $table->foreignId('server_id'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('standalone_dockers'); + } +}; diff --git a/database/migrations/2023_03_27_085023_create_swarm_dockers_table.php b/database/migrations/2023_03_27_085023_create_swarm_dockers_table.php new file mode 100644 index 000000000..44e38e3c5 --- /dev/null +++ b/database/migrations/2023_03_27_085023_create_swarm_dockers_table.php @@ -0,0 +1,30 @@ +id(); + $table->string('uuid')->unique(); + + $table->foreignId('server_id'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('swarm_dockers'); + } +}; diff --git a/database/migrations/2023_03_28_062150_create_kubernetes_table.php b/database/migrations/2023_03_28_062150_create_kubernetes_table.php new file mode 100644 index 000000000..42ef4770a --- /dev/null +++ b/database/migrations/2023_03_28_062150_create_kubernetes_table.php @@ -0,0 +1,27 @@ +id(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('kubernetes'); + } +}; diff --git a/database/seeders/ApplicationSeeder.php b/database/seeders/ApplicationSeeder.php new file mode 100644 index 000000000..ded229b65 --- /dev/null +++ b/database/seeders/ApplicationSeeder.php @@ -0,0 +1,37 @@ + 1, + 'name' => 'My first application', + 'environment_id' => $environment_1->id, + 'destination_id' => $standalone_docker_1->id, + 'destination_type' => StandaloneDocker::class, + ]); + Application::create([ + 'id' => 2, + 'name' => 'My second application (Swarm)', + 'environment_id' => $environment_1->id, + 'destination_id' => $swarm_docker_1->id, + 'destination_type' => SwarmDocker::class, + ]); + } +} diff --git a/database/seeders/DBSeeder.php b/database/seeders/DBSeeder.php new file mode 100644 index 000000000..68bbeb01c --- /dev/null +++ b/database/seeders/DBSeeder.php @@ -0,0 +1,24 @@ + 1, + 'name'=> "My first database", + 'environment_id' => $environment_1->id, + 'destination_id' => $standalone_docker_1->id, + 'destination_type' => StandaloneDocker::class, + ]); + } +} diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 19606f85a..674153fd0 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -2,6 +2,7 @@ namespace Database\Seeders; +use App\Models\StandaloneDocker; use Illuminate\Database\Seeder; class DatabaseSeeder extends Seeder @@ -12,8 +13,17 @@ class DatabaseSeeder extends Seeder $this->call([ UserSeeder::class, TeamSeeder::class, - ServerSeeder::class, PrivateKeySeeder::class, + ServerSeeder::class, + ProjectSeeder::class, + ProjectSettingSeeder::class, + EnvironmentSeeder::class, + StandaloneDockerSeeder::class, + SwarmDockerSeeder::class, + KubernetesSeeder::class, + ApplicationSeeder::class, + DBSeeder::class, + ServiceSeeder::class, ]); } } diff --git a/database/seeders/EnvironmentSeeder.php b/database/seeders/EnvironmentSeeder.php new file mode 100644 index 000000000..d3dfc8c63 --- /dev/null +++ b/database/seeders/EnvironmentSeeder.php @@ -0,0 +1,29 @@ + 1, + 'name' => 'production', + 'project_id' => $project_1->id, + ]); + Environment::create([ + 'id' => 2, + 'name' => 'staging', + 'project_id' => $project_1->id, + ]); + } +} diff --git a/database/seeders/KubernetesSeeder.php b/database/seeders/KubernetesSeeder.php new file mode 100644 index 000000000..e43a8df60 --- /dev/null +++ b/database/seeders/KubernetesSeeder.php @@ -0,0 +1,17 @@ + "Testing-host", "description" => "This is a test docker container", "private_key" => "-----BEGIN OPENSSH PRIVATE KEY----- @@ -26,9 +24,7 @@ hwAAAAtzc2gtZWQyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevA AAAECBQw4jg1WRT2IGHMncCiZhURCts2s24HoDS0thHnnRKVuGmoeGq/pojrsyP1pszcNV uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA== -----END OPENSSH PRIVATE KEY----- -", +" ]); - $server->privateKeys()->attach($private_key); - $server2->privateKeys()->attach($private_key); } } diff --git a/database/seeders/ProjectSeeder.php b/database/seeders/ProjectSeeder.php new file mode 100644 index 000000000..c43a69e5c --- /dev/null +++ b/database/seeders/ProjectSeeder.php @@ -0,0 +1,21 @@ + 1, + 'name' => "My first project", + 'description' => "This is a test project in development", + 'team_id' => $root_team->id, + ]); + } +} diff --git a/database/seeders/ProjectSettingSeeder.php b/database/seeders/ProjectSettingSeeder.php new file mode 100644 index 000000000..050982bee --- /dev/null +++ b/database/seeders/ProjectSettingSeeder.php @@ -0,0 +1,20 @@ + 1, + 'wildcard_domain' => 'testing-host.localhost', + 'project_id' => $first_project->id, + ]); + } +} diff --git a/database/seeders/ServerSeeder.php b/database/seeders/ServerSeeder.php index 22fb68a03..2d14bd199 100644 --- a/database/seeders/ServerSeeder.php +++ b/database/seeders/ServerSeeder.php @@ -2,10 +2,12 @@ namespace Database\Seeders; +use App\Models\PrivateKey; use App\Models\Server; use App\Models\Team; use Illuminate\Database\Console\Seeds\WithoutModelEvents; use Illuminate\Database\Seeder; +use Illuminate\Support\Facades\DB; class ServerSeeder extends Seeder { @@ -15,12 +17,14 @@ class ServerSeeder extends Seeder public function run(): void { $root_team = Team::find(1); - Server::create([ + $private_key_1 = PrivateKey::find(1); + $server_1 = Server::create([ 'id' => 1, 'name' => "testing-host", 'description' => "This is a test docker container", 'ip' => "coolify-testing-host", 'team_id' => $root_team->id, + 'private_key_id' => $private_key_1->id, ]); Server::create([ 'id' => 2, @@ -28,6 +32,8 @@ class ServerSeeder extends Seeder 'description' => "This is a test docker container", 'ip' => "coolify-testing-host-2", 'team_id' => $root_team->id, + 'private_key_id' => $private_key_1->id, ]); + } } diff --git a/database/seeders/ServiceSeeder.php b/database/seeders/ServiceSeeder.php new file mode 100644 index 000000000..e3e1ea3d8 --- /dev/null +++ b/database/seeders/ServiceSeeder.php @@ -0,0 +1,27 @@ + 1, + 'name'=> "My first database", + 'environment_id' => $environment_1->id, + 'destination_id' => $standalone_docker_1->id, + 'destination_type' => StandaloneDocker::class, + ]); + } +} diff --git a/database/seeders/StandaloneDockerSeeder.php b/database/seeders/StandaloneDockerSeeder.php new file mode 100644 index 000000000..17b764ba7 --- /dev/null +++ b/database/seeders/StandaloneDockerSeeder.php @@ -0,0 +1,24 @@ + 1, + 'server_id' => $server_1->id, + ]); + } +} diff --git a/database/seeders/SwarmDockerSeeder.php b/database/seeders/SwarmDockerSeeder.php new file mode 100644 index 000000000..2d1a87b53 --- /dev/null +++ b/database/seeders/SwarmDockerSeeder.php @@ -0,0 +1,25 @@ + 1, + 'server_id' => $server_1->id, + ]); + } +} diff --git a/resources/views/components/navbar.blade.php b/resources/views/components/navbar.blade.php index 008e4a57b..14507b8a6 100644 --- a/resources/views/components/navbar.blade.php +++ b/resources/views/components/navbar.blade.php @@ -1,10 +1,10 @@