From 6e3b19a5aacf2766070ae12e5aae0f0852a7e100 Mon Sep 17 00:00:00 2001 From: Vincent BRIDIER Date: Thu, 5 Sep 2024 13:51:44 +0200 Subject: [PATCH] feat: :sparkles: :memo: - Add command for Showroom BO Instanciation --- README.md | 12 + app/Console/Commands/SetGitlabCdVariables.php | 76 +-- app/Console/Commands/ShowroomBoSetup.php | 466 ++++++++++++++++++ app/Lib/CdEnvVariable.php | 2 +- app/Lib/Common.php | 22 + app/Lib/Gitlab.php | 113 +++++ app/Objects/Gitlab/Schedule.php | 45 ++ config/filesystems.php | 6 + config/gitlab.php | 4 + phpcs.xml | 1 - resources/gitlab_exports/showroom-bo.tar.gz | Bin 0 -> 28411 bytes 11 files changed, 683 insertions(+), 64 deletions(-) create mode 100644 app/Console/Commands/ShowroomBoSetup.php create mode 100644 app/Lib/Common.php create mode 100644 app/Lib/Gitlab.php create mode 100644 app/Objects/Gitlab/Schedule.php create mode 100644 resources/gitlab_exports/showroom-bo.tar.gz diff --git a/README.md b/README.md index 04aece6..09322b3 100644 --- a/README.md +++ b/README.md @@ -14,3 +14,15 @@ or `artisan uwil:gitlab:set_variables -P project_id` + +### Showroom BO Instances + +```bash +artisan uwil:gitlab:showroom-bo-setup "BRAND NAME" +ex: +artisan uwil:gitlab:showroom-bo-setup "Nature and Respect" +``` + +## Available cert issuers + +[Documentation here](https://lab.s-web.fr/ldc-web/general/documentation/-/wikis/Deployment#available-cert-issuers) diff --git a/app/Console/Commands/SetGitlabCdVariables.php b/app/Console/Commands/SetGitlabCdVariables.php index 25b2b26..0012b12 100644 --- a/app/Console/Commands/SetGitlabCdVariables.php +++ b/app/Console/Commands/SetGitlabCdVariables.php @@ -4,13 +4,14 @@ namespace App\Console\Commands; use App\Enums\EnvironmentScope; use App\Lib\CdEnvVariable; +use App\Lib\Common; +use App\Lib\Gitlab; use GrahamCampbell\GitLab\GitLabManager; use Illuminate\Console\Command; use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Validator; use Illuminate\Support\Str; -use Illuminate\Encryption\Encrypter; use Illuminate\Validation\ValidationException; use Psy\Readline\Hoa\ConsoleException; use SebastianBergmann\Diff\Differ; @@ -94,7 +95,7 @@ class SetGitlabCdVariables extends Command 'APP_KEY' => (new CdEnvVariable( environment_scope: EnvironmentScope::all, key: 'APP_KEY', - value: $this->generateRandomKey(), + value: Common::generateRandomKey(), protected: true, masked: true, ))->isProjectDefault()->wasPrefixed(), @@ -296,11 +297,11 @@ class SetGitlabCdVariables extends Command * * ! This command may throw exceptions if there is a unhandled difference between actual vars and template. * - * @return void + * @return integer * @throws \RuntimeException If an error occurs while comunicating with gitlab. * @throws \Psy\Readline\Hoa\ConsoleException If the user cancels this command. */ - public function handle(): void + public function handle(): int { $this->warn( '! This command may throw exceptions if there is a unhandled difference between actual vars and template.' @@ -395,55 +396,20 @@ class SetGitlabCdVariables extends Command // * Remove existing vars before inserting all $this->removeExistingProjectCdVars($projectId); - $this->saveProjectCdVarsToGitlab($projectId, $newVars); - - $this->info('Done !!!'); - $this->info('Please check on ' . $this->getProjetCdVarsUrl($projectId)); - } - - // * PRIVATE GITLAB - - /** - * Save compiled vars on Gitlab project - * - * @param integer $projectId - * @param array> $newVars - * @return void - */ - private function saveProjectCdVarsToGitlab(int $projectId, array $newVars): void - { - try { - $updateProjectVar = function (int $projectId, CdEnvVariable $var) { - $this->client->projects()->addVariable( - $projectId, - $var->getFormatedGitlabKey(), - $var->value, - $var->protected, - $var->environment_scope->value, - [ - 'masked' => $var->masked, - 'raw' => $var->raw - ] - ); - }; - foreach ($newVars as $varOrVarList) { - if ($varOrVarList instanceof CdEnvVariable) { - $updateProjectVar($projectId, $varOrVarList); - continue; - } - foreach ($varOrVarList as $var) { - $updateProjectVar($projectId, $var); - } - } - } catch (\Exception $e) { + if (!Gitlab::saveProjectCdVarsToGitlab($projectId, $newVars)) { $this->warn( 'Sorry an error just happened, please check actual env vars to prevent project crash ok k8s' ); - dump($e); - exit; - } //end try + return 1; + } + + $this->info('Done !!!'); + $this->info('Please check on ' . $this->getProjetCdVarsUrl($projectId)); + return 0; } + // * PRIVATE GITLAB + /** * Remove all existing project CD vars * @@ -848,18 +814,4 @@ class SetGitlabCdVariables extends Command }; //end while return $value; } - - /** - * Generate a random key for the application. - * - * ! Copy from \Illuminate\Foundation\Console\KeyGenerateCommand - * - * @return string - */ - protected function generateRandomKey() - { - return 'base64:' . base64_encode( - Encrypter::generateKey(config('app.cipher')) - ); - } } diff --git a/app/Console/Commands/ShowroomBoSetup.php b/app/Console/Commands/ShowroomBoSetup.php new file mode 100644 index 0000000..a68b20b --- /dev/null +++ b/app/Console/Commands/ShowroomBoSetup.php @@ -0,0 +1,466 @@ +> + * Keyed with `\App\Enums\EnvironmentScope`. + */ + private static array $defaultEnvVars = []; + + /** + * Execute the console command. + * + * @return integer + */ + public function handle(): int + { + $name = $this->argument('name'); + + $this->info("Template upload..."); + $templateUpload = $this->uploadTemplate($name); + if (!$templateUpload->created()) { + $this->error("Error occured on template upload. See logs."); + return 1; + } + $projectId = $templateUpload->collect()->get('id'); + $this->info("Template uploaded."); + $this->info("Setting vars..."); + $this->setDefaultVars($name); + $this->info("Vars are set."); + $this->info("Vars upload..."); + if (!Gitlab::saveProjectCdVarsToGitlab($projectId, self::$defaultEnvVars)) { + $this->warn( + 'Sorry an error just happened, please check actual env vars to prevent project crash ok k8s' + ); + return 1; + } + $this->info("Vars uploaded."); + $this->info("Schedules upload..."); + if ( + !Gitlab::setPipelineSchedules($projectId, new Schedule( + '0 14 * * *', + "Deploy STAGING", + "trunk", + false, + 'Europe/Paris' + )) + ) { + $this->warn( + 'Sorry an error just happened on STAGING Schedule upload' + ); + return 1; + } + if ( + !Gitlab::setPipelineSchedules($projectId, new Schedule( + '0 14 * * *', + "Deploy PRODUCTION", + "master", + false, + 'Europe/Paris' + )) + ) { + $this->warn( + 'Sorry an error just happened on PRODUCTION Schedule upload' + ); + return 1; + } + $this->info("Schedules uploaded."); + $this->newLine(); + $this->info("Instance created successfully! Think to set the secret variables before running the pipelines"); + return 0; + } + + /** + * uploadTemplate method + * + * @param string $name + * @return \Illuminate\Http\Client\Response + */ + private function uploadTemplate(string $name): \Illuminate\Http\Client\Response + { + /** + * https://docs.gitlab.com/ee/api/project_import_export.html#import-a-file + * + * file string The file to be uploaded. REQUIRED + * path string Name and path for new project. REQUIRED + * name string The name of the project to be imported. Defaults to the path of the project if not provided. + * namespace integer or string The ID or path of the namespace to import the project to. + * Defaults to the current user's namespace. + * Requires at least the Maintainer role on the destination group to import to. + */ + $file = fopen(Storage::disk('gitlabExports')->path('showroom-bo.tar.gz'), 'r'); + $response = Http::withHeaders([ + 'Private-Token' => config('gitlab.connections.main.token') + ])->attach( + 'file', + $file, + 'showroom-bo.tar.gz' + )->post( + sprintf( + "%s/api/v4/projects/import", + config('gitlab.connections.main.url') + ), + [ + 'path' => Str::slug($name), + 'name' => $name, + 'namespace' => config('gitlab.showroom-bo.instances_group_id') + ] + ); + + return $response; + } + + /** + * setDefaultVars method + * + * @param string $name + * @return void + */ + private function setDefaultVars(string $name): void + { + // * Init default vars reference + if (empty(self::$defaultEnvVars)) { + self::$defaultEnvVars = [ + 'APP_NAME' => (new CdEnvVariable( + environment_scope: EnvironmentScope::all, + key: 'APP_NAME', + value: $name, + protected: true, + ))->isProjectDefault(), + 'APP_ENV' => [ + EnvironmentScope::staging->value => (new CdEnvVariable( + environment_scope: EnvironmentScope::staging, + key: 'APP_ENV', + value: 'staging', + protected: true, + ))->isProjectDefault(), + EnvironmentScope::production->value => (new CdEnvVariable( + environment_scope: EnvironmentScope::production, + key: 'APP_ENV', + value: 'production', + protected: true, + masked: true, + ))->isProjectDefault(), + ], + 'APP_KEY' => (new CdEnvVariable( + environment_scope: EnvironmentScope::all, + key: 'APP_KEY', + value: Common::generateRandomKey(), + protected: true, + masked: true, + ))->isProjectDefault(), + 'APP_DEBUG' => [ + EnvironmentScope::staging->value => (new CdEnvVariable( + environment_scope: EnvironmentScope::staging, + key: 'APP_DEBUG', + value: 'false', + protected: true, + ))->isProjectDefault(), + EnvironmentScope::production->value => (new CdEnvVariable( + environment_scope: EnvironmentScope::production, + key: 'APP_DEBUG', + value: 'false', + protected: true, + ))->isProjectDefault(), + ], + 'DOMAIN' => [ + EnvironmentScope::staging->value => (new CdEnvVariable( + environment_scope: EnvironmentScope::staging, + key: 'DOMAIN', + value: '$CI_PROJECT_NAME-expo.re7-s-web.fr', + protected: true, + masked: true, + raw: true, + ))->isProjectDefault(), + EnvironmentScope::production->value => (new CdEnvVariable( + environment_scope: EnvironmentScope::production, + key: 'DOMAIN', + value: sprintf( + "%s-expo.uwil.fr", + Str::slug($name) + ), + protected: true, + masked: true, + ))->isProjectDefault(), + ], + 'DB_DATABASE' => [ + EnvironmentScope::staging->value => (new CdEnvVariable( + environment_scope: EnvironmentScope::staging, + key: 'DB_DATABASE', + value: sprintf( + "staging-expo-%s", + Str::slug($name) + ), + protected: true, + masked: true, + ))->isProjectDefault(), + EnvironmentScope::production->value => (new CdEnvVariable( + environment_scope: EnvironmentScope::production, + key: 'DB_DATABASE', + value: sprintf( + "prod-expo-%s", + Str::slug($name) + ), + protected: true, + masked: true, + ))->isProjectDefault(), + ], + 'DB_USERNAME' => [ + EnvironmentScope::staging->value => (new CdEnvVariable( + environment_scope: EnvironmentScope::staging, + key: 'DB_USERNAME', + value: sprintf( + "staging-expo-%s", + Str::slug($name) + ), + protected: true, + masked: true, + ))->isProjectDefault(), + EnvironmentScope::production->value => (new CdEnvVariable( + environment_scope: EnvironmentScope::production, + key: 'DB_USERNAME', + value: sprintf( + "prod-expo-%s", + Str::slug($name) + ), + protected: true, + masked: true, + ))->isProjectDefault(), + ], + 'DB_PASSWORD' => [ + EnvironmentScope::staging->value => (new CdEnvVariable( + environment_scope: EnvironmentScope::staging, + key: 'DB_PASSWORD', + value: 'changeme', + protected: true, + masked: true, + ))->isProjectDefault(), + EnvironmentScope::production->value => (new CdEnvVariable( + environment_scope: EnvironmentScope::production, + key: 'DB_PASSWORD', + value: 'changeme', + protected: true, + masked: true, + ))->isProjectDefault(), + ], + 'MAIL_ENCRYPTION' => [ + EnvironmentScope::staging->value => (new CdEnvVariable( + environment_scope: EnvironmentScope::staging, + key: 'MAIL_ENCRYPTION', + value: 'null', + protected: true, + ))->isProjectDefault(), + EnvironmentScope::production->value => (new CdEnvVariable( + environment_scope: EnvironmentScope::production, + key: 'MAIL_ENCRYPTION', + value: 'tls', + protected: true, + ))->isProjectDefault(), + ], + 'MAIL_HOST' => [ + EnvironmentScope::staging->value => (new CdEnvVariable( + environment_scope: EnvironmentScope::staging, + key: 'MAIL_HOST', + value: 'null', + protected: true, + ))->isProjectDefault(), + EnvironmentScope::production->value => (new CdEnvVariable( + environment_scope: EnvironmentScope::production, + key: 'MAIL_HOST', + value: 'smtp-relay.brevo.com', + protected: true, + masked: true, + ))->isProjectDefault(), + ], + 'MAIL_PORT' => [ + EnvironmentScope::staging->value => (new CdEnvVariable( + environment_scope: EnvironmentScope::staging, + key: 'MAIL_PORT', + value: 'null', + protected: true, + ))->isProjectDefault(), + EnvironmentScope::production->value => (new CdEnvVariable( + environment_scope: EnvironmentScope::production, + key: 'MAIL_PORT', + value: '587', + protected: true, + ))->isProjectDefault(), + ], + 'MAIL_USERNAME' => [ + EnvironmentScope::staging->value => (new CdEnvVariable( + environment_scope: EnvironmentScope::staging, + key: 'MAIL_USERNAME', + value: 'null', + protected: true, + ))->isProjectDefault(), + EnvironmentScope::production->value => (new CdEnvVariable( + environment_scope: EnvironmentScope::production, + key: 'MAIL_USERNAME', + value: 'changeme', + protected: true, + masked: true, + ))->isProjectDefault(), + ], + 'MAIL_PASSWORD' => [ + EnvironmentScope::staging->value => (new CdEnvVariable( + environment_scope: EnvironmentScope::staging, + key: 'MAIL_PASSWORD', + value: 'null', + protected: true, + ))->isProjectDefault(), + EnvironmentScope::production->value => (new CdEnvVariable( + environment_scope: EnvironmentScope::production, + key: 'MAIL_PASSWORD', + value: 'changeme', + protected: true, + masked: true, + ))->isProjectDefault(), + ], + 'MAIL_FROM_ADDRESS' => (new CdEnvVariable( + environment_scope: EnvironmentScope::all, + key: 'MAIL_FROM_ADDRESS', + value: 'no-reply@uwil.fr', + protected: true, + masked: true, + ))->isProjectDefault(), + 'LDC_WEB_API_KEY' => (new CdEnvVariable( + environment_scope: EnvironmentScope::all, + key: 'LDC_WEB_API_KEY', + value: 'changeme', + protected: true, + masked: true, + ))->isProjectDefault(), + 'SENTRY_LARAVEL_DSN' => (new CdEnvVariable( + environment_scope: EnvironmentScope::all, + key: 'SENTRY_LARAVEL_DSN', + value: 'changeme', + protected: true, + masked: true, + ))->isProjectDefault(), + 'SAML2_SP_CERT_x509' => [ + EnvironmentScope::staging->value => (new CdEnvVariable( + environment_scope: EnvironmentScope::staging, + key: 'SAML2_SP_CERT_x509', + value: 'changeme', + protected: true, + masked: true, + ))->isProjectDefault(), + EnvironmentScope::production->value => (new CdEnvVariable( + environment_scope: EnvironmentScope::production, + key: 'SAML2_SP_CERT_x509', + value: 'changeme', + protected: true, + masked: true, + ))->isProjectDefault(), + ], + 'SAML2_SP_CERT_PRIVATEKEY' => [ + EnvironmentScope::staging->value => (new CdEnvVariable( + environment_scope: EnvironmentScope::staging, + key: 'SAML2_SP_CERT_PRIVATEKEY', + value: 'changeme', + protected: true, + masked: true, + ))->isProjectDefault(), + EnvironmentScope::production->value => (new CdEnvVariable( + environment_scope: EnvironmentScope::production, + key: 'SAML2_SP_CERT_PRIVATEKEY', + value: 'changeme', + protected: true, + masked: true, + ))->isProjectDefault(), + ], + 'SAML2_CONTACT_TECHNICAL_EMAIL' => (new CdEnvVariable( + environment_scope: EnvironmentScope::all, + key: 'SAML2_CONTACT_TECHNICAL_EMAIL', + value: 'changeme', + protected: true, + masked: true, + ))->isProjectDefault(), + 'SAML2_CONTACT_SUPPORT_EMAIL' => (new CdEnvVariable( + environment_scope: EnvironmentScope::all, + key: 'SAML2_CONTACT_SUPPORT_EMAIL', + value: 'changeme', + protected: true, + masked: true, + ))->isProjectDefault(), + 'SAML2_DEFAULT_TENANT_UUID' => (new CdEnvVariable( + environment_scope: EnvironmentScope::all, + key: 'SAML2_DEFAULT_TENANT_UUID', + value: 'support', + protected: true, + ))->isProjectDefault(), + 'PVC_SIZE' => (new CdEnvVariable( + environment_scope: EnvironmentScope::all, + key: 'PVC_SIZE', + value: '3Gi', + protected: true, + ))->isProjectDefault(), + 'IMAGE_TAG' => [ + EnvironmentScope::staging->value => (new CdEnvVariable( + environment_scope: EnvironmentScope::staging, + key: 'IMAGE_TAG', + value: 'changeme', + protected: true, + masked: true, + )), + EnvironmentScope::production->value => (new CdEnvVariable( + environment_scope: EnvironmentScope::production, + key: 'IMAGE_TAG', + value: 'changeme', + protected: true, + masked: true, + )), + ], + 'CERT_ISSUER' => [ + EnvironmentScope::staging->value => (new CdEnvVariable( + environment_scope: EnvironmentScope::staging, + key: 'CERT_ISSUER', + value: 're7-letsencrypt-production-dns01', + protected: true, + masked: true, + ))->isProjectDefault(), + EnvironmentScope::production->value => (new CdEnvVariable( + environment_scope: EnvironmentScope::production, + key: 'CERT_ISSUER', + value: 'letsencrypt-production-dns01', + protected: true, + masked: true, + ))->isProjectDefault(), + ], + ]; + self::$defaultEnvVars = Arr::sortRecursive(self::$defaultEnvVars); + } //end if + } +} diff --git a/app/Lib/CdEnvVariable.php b/app/Lib/CdEnvVariable.php index 44d4426..5393fc2 100644 --- a/app/Lib/CdEnvVariable.php +++ b/app/Lib/CdEnvVariable.php @@ -35,7 +35,7 @@ class CdEnvVariable implements \Stringable * * @var string */ - private static string $prefix = '1_LRVL'; + private static string $prefix = 'APP'; /** * The variable is default diff --git a/app/Lib/Common.php b/app/Lib/Common.php new file mode 100644 index 0000000..56012da --- /dev/null +++ b/app/Lib/Common.php @@ -0,0 +1,22 @@ +> $newVars + * @return boolean + */ + public static function saveProjectCdVarsToGitlab(int $projectId, array $newVars): bool + { + self::getInstance(); + try { + $updateProjectVar = function (int $projectId, CdEnvVariable $var) { + Log::debug( + sprintf( + "Add variable %s with value %s", + $var->key, + $var->value + ) + ); + self::$client->projects()->addVariable( + $projectId, + $var->getFormatedGitlabKey(), + $var->value, + $var->protected, + $var->environment_scope->value, + [ + 'masked' => $var->masked, + 'raw' => $var->raw + ] + ); + }; + foreach ($newVars as $varOrVarList) { + if ($varOrVarList instanceof CdEnvVariable) { + $updateProjectVar($projectId, $varOrVarList); + continue; + } + foreach ($varOrVarList as $var) { + $updateProjectVar($projectId, $var); + } + } + } catch (\Exception $e) { + Log::critical($e->getMessage()); + return false; + } //end try + return true; + } + + /** + * setPipelineSchedules method + * + * @param integer $projectId + * @param \App\Objects\Gitlab\Schedule $schedule + * @return boolean + */ + public static function setPipelineSchedules(int $projectId, Schedule $schedule): bool + { + self::getInstance(); + try { + self::$client->schedules()->create($projectId, $schedule->toArray()); + } catch (\Exception $e) { + Log::critical($e->getMessage()); + return false; + } //end try + return true; + } +} diff --git a/app/Objects/Gitlab/Schedule.php b/app/Objects/Gitlab/Schedule.php new file mode 100644 index 0000000..2237644 --- /dev/null +++ b/app/Objects/Gitlab/Schedule.php @@ -0,0 +1,45 @@ + $this->cron, + 'description' => $this->description, + 'ref' => $this->ref, + 'active' => $this->active, + 'cron_timezone' => $this->cron_timezone + ]; + } +} diff --git a/config/filesystems.php b/config/filesystems.php index e99cd57..b0e64dd 100644 --- a/config/filesystems.php +++ b/config/filesystems.php @@ -56,6 +56,12 @@ return [ 'throw' => false, ], + 'gitlabExports' => [ + 'driver' => 'local', + 'root' => resource_path('gitlab_exports'), + 'throw' => false, + ] + ], /* diff --git a/config/gitlab.php b/config/gitlab.php index 59b00a6..410a9a3 100644 --- a/config/gitlab.php +++ b/config/gitlab.php @@ -67,4 +67,8 @@ return [ ], + 'showroom-bo' => [ + 'instances_group_id' => env('GITLAB_SHOWROOM_INSTANCE_GROUP_ID', 286) + ] + ]; diff --git a/phpcs.xml b/phpcs.xml index 3e28d83..c00d4c3 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -6,7 +6,6 @@ app/ config/ - database/factories routes/ diff --git a/resources/gitlab_exports/showroom-bo.tar.gz b/resources/gitlab_exports/showroom-bo.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..c424c1b1d6a8fc23218f1523d04f6deb218f1e8c GIT binary patch literal 28411 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 Tck#jgj^dra6Z{Dm=F|TGoCrDD literal 0 HcmV?d00001