Skip to content
Snippets Groups Projects
Handler.php 33.6 KiB
Newer Older
jurgenhaas's avatar
jurgenhaas committed
<?php

namespace LakeDrops\Docker4Drupal;

use Henrywhitaker3\Healthchecks\Exceptions\HealthchecksAccountLimitReachedException;
use Henrywhitaker3\Healthchecks\Exceptions\HealthchecksFailureException;
use Henrywhitaker3\Healthchecks\Exceptions\HealthchecksUnauthorisedException;
use Henrywhitaker3\Healthchecks\Exceptions\HealthchecksUuidNotFoundException;
use Henrywhitaker3\Healthchecks\Healthchecks;
use Henrywhitaker3\Healthchecks\HealthchecksManager;
use LakeDrops\Component\Composer\BaseHandler;
use LakeDrops\DockerTraefik\Traefik;
use LakeDrops\DrupalEnvironment\Handler as DrupalEnvironment;
jurgenhaas's avatar
jurgenhaas committed
use Symfony\Component\Filesystem\Filesystem;
jurgenhaas's avatar
jurgenhaas committed

jurgenhaas's avatar
jurgenhaas committed
/**
jurgenhaas's avatar
jurgenhaas committed
 *
 * @package LakeDrops\Docker4Drupal
 */
class Handler extends BaseHandler {
jurgenhaas's avatar
jurgenhaas committed

  public function configId(): string {
    return 'docker4drupal';
  }

  /**
   * {@inheritdoc}
   */
  protected function configDefault(): array {
    $dockerImageProxy = getenv('DOCKER_IMAGE_PREFIX');
    if (!empty($dockerImageProxy)) {
      $dockerImageProxy = str_replace('//', '/', $dockerImageProxy . '/');
    }
    $projectname = getenv('COMPOSE_PROJECT_NAME');
jurgenhaas's avatar
jurgenhaas committed
    if (empty($projectname)) {
      $projectname = str_replace([' ', '-', '_', '.'], '', basename(getcwd()));
      $this->env->put('COMPOSE_PROJECT_NAME', $projectname);
    }
    $traefik_env = [];
    $i = 1;
    while ($item = $this->env->receive('traefik_env_' . $i, '', '0')) {
      [$key, $value] = explode(':', $item);
      $traefik_env[$key] = $value;
      $i++;
    }
    return [
      'projectname' => $projectname,
jurgenhaas's avatar
jurgenhaas committed
      'staging' => FALSE,
jurgenhaas's avatar
jurgenhaas committed
      'basicauth' => [
        'enable' => FALSE,
jurgenhaas's avatar
jurgenhaas committed
        'user' => '',
        'pass' => '',
        'code' => '',
jurgenhaas's avatar
jurgenhaas committed
      ],
      'ci_home' => '/home/gitlab-runner',
      'docker0' => [
        'ip' => ($this->isCiContext() || $this->isLocalDevMode()) ? $this->getDockerGateway() : $this->getLocalIpv4('docker0'),
        'proxy' => ($this->isCiContext() || $this->isLocalDevMode()) ? $this->getDockerProxy() : FALSE,
      'traefik' => [
        'domain' => $this->env->receive('traefik_domain', '', 'docker.localhost'),
        'usessl' => $this->env->receive('traefik_usessl', '', '0'),
        'port' => $this->env->receive('traefik_port', '', '8000'),
        'ports' => $this->env->receive('traefik_ports', '', '8443'),
        'cert' => $this->env->receive('traefik_cert', ''),
        'key' => $this->env->receive('traefik_key', ''),
        'portainer' => $this->env->receive('traefik_portainer', '', '0'),
        'hub_token' => $this->env->receive('traefik_hub_token', ''),
        'dns_challenge' => $this->env->receive('traefik_dns_challenge', '', '0'),
        'dns_challenge_provider' => $this->env->receive('traefik_dns_challenge_provider', ''),
        'dns_challenge_resolver' => $this->env->receive('traefik_dns_challenge_resolver', ''),
        'env' => $traefik_env,
      'live' => [
        'root' => '',
        'uri' => '',
        'host' => '',
        'user' => $this->env->receive('live_host_username', 'Remote username for host of the live site', getenv('USER')),
      ],
      'drush' => [
        'sql' => [
          'tables' => [
            'structure' => [
              'cache',
              'cachetags',
              'cache_*',
              'history',
              'search_*',
              'sessions',
              'watchdog',
            ],
            'skip' => [
              'migration_*',
            ],
          ],
        ],
      ],
      'drupal' => [
        'version' => $this->env->receiveGlobal('PHP_VERSION', 'PHP version', '8.1'),
        'xdebug' => $this->env->receiveGlobal('PHP_DEBUG', 'PHP debug', '0'),
        'coverage' => $this->env->receiveGlobal('PHP_COVERAGE', 'PHP coverage', '0'),
        'profiler' => $this->env->receiveGlobal('PHP_PROFILER', 'PHP PROFILER', '0'),
        'localip' => $this->env->receiveGlobal('LOCAL_IP', 'Local IP', '0'),
        'related_subdomains' => [],
        'version' => '10.6',
      'webserver' => [
        'type' => 'apache',
        'overwriteconfig' => FALSE,
        'responseheader' => [
          'server' => '',
          'strict_transport_security' => 'max-age=31536000; includeSubDomains',
          'referrer_policy' => 'same-origin',
          'permissions_policy' => 'accelerometer=(), camera=(), geolocation=(), gyroscope=(), microphone=(), payment=(), usb=()',
          'cross_origin_embedder_policy' => 'credentialless',
          'cross_origin_opener_policy' => 'same-origin',
          'cross_origin_resource_policy' => 'cross-origin',
          'x_permitted_cross_domain_policies' => 'none',
        ],
        'host' => $this->env->receiveGlobal('MAILHOG_HOST', 'MailHog Host', 'smtp.freesmtpservers.com'),
        'port' => $this->env->receiveGlobal('MAILHOG_PORT', 'MailHog Port', '25'),
        'username' => $this->env->receiveGlobal('MAILHOG_USERNAME', 'MailHog Username'),
        'password' => $this->env->receiveGlobal('MAILHOG_PASSWORD', 'MailHog Password'),
        'mechanism' => $this->env->receiveGlobal('MAILHOG_MECHANISM', 'MailHog Auth Mechanism', 'NONE'),
      'mailpit' => [
        'enable' => 1,
        'host' => $this->env->receiveGlobal('MAILPIT_HOST', 'MailPit Host', 'smtp.freesmtpservers.com'),
        'port' => $this->env->receiveGlobal('MAILPIT_PORT', 'MailPit Port', '25'),
        'username' => $this->env->receiveGlobal('MAILPIT_USERNAME', 'MailPit Username'),
        'password' => $this->env->receiveGlobal('MAILPIT_PASSWORD', 'MailPit Password'),
        'starttls' => $this->env->receiveGlobal('MAILPIT_STARTTLS', 'MailPit StartTLS'),
        'allowinsecure' => $this->env->receiveGlobal('MAILPIT_ALLOW_INSECURE', 'MailPit allow insecure'),
        'auth' => $this->env->receiveGlobal('MAILPIT_AUTH', 'MailPit Auth (none|plain|login|cram-md5)'),
        'secret' => $this->env->receiveGlobal('MAILPIT_SECRET', 'MailPit Secret'),
        'returnpath' => $this->env->receiveGlobal('MAILPIT_RETURNPATH', 'MailPit Bounce Address'),
        'recipientallowlist' => $this->env->receiveGlobal('MAILPIT_RECIPIENT_ALLOW_LIST', 'MailPit Regex for allowed recipients'),
      ],
      'symfony_mailer' => [
        'enable' => 0,
        'host' => '',
        'port' => 25,
        'username' => '',
        'password' => '',
      ],
      'varnish' => [
        'enable' => 0,
      ],
      'redis' => [
      ],
      'dbbrowser' => [
        'type' => 'pma',
      ],
      'solr' => [
        'enable' => 0,
      ],
      'node' => [
        'enable' => 0,
        'key' => '',
        'path' => '',
      ],
      'memcached' => [
        'enable' => 0,
      ],
      'rsyslog' => [
        'enable' => 0,
      ],
      'athenapdf' => [
        'enable' => 0,
        'key' => '',
      ],
      'blackfire' => [
        'enable' => 0,
        'id' => '',
        'token' => '',
      ],
      'webgrind' => [
        'enable' => 0,
      ],
      'selenium' => [
        'enable' => 0,
      ],
      'elasticsearch' => [
        'enable' => 0,
      ],
      'wkhtmltox' => [
        'enable' => 0,
      ],
      'backstop' => $this->backstopDefaults(),
jurgenhaas's avatar
jurgenhaas committed
      'crontabs' => [
jurgenhaas's avatar
jurgenhaas committed
      ],
      'backup' => [
        'enable' => FALSE,
        'crontime' => '50 */6 * * *',
        'crontimecheck' => '30 23 1 * *',
jurgenhaas's avatar
jurgenhaas committed
        'remoterepo' => FALSE,
        'retention' => [
          'hourly' => 2,
          'daily' => 7,
          'weekly' => 8,
          'monthly' => 12,
          'yearly' => 30,
        ],
      ],
jurgenhaas's avatar
jurgenhaas committed
      'cypress' => [
        'enable' => $this->env->receiveGlobal('CYPRESS', 'Cypress', '0'),
        'version' => 'latest',
jurgenhaas's avatar
jurgenhaas committed
      ],
      'unlighthouse' => [
        'enable' => $this->env->receiveGlobal('UNLIGHTHOUSE', 'Unlighthouse', '0'),
        'urlprefix' => '',
      'invoiceninja' => [
        'enable' => 0,
      ],
  }

  /**
   * {@inheritdoc}
   */
  protected function postInit(): void {
    $this->env->put('PHP_VERSION', $this->config->readValue(['php', 'version']), TRUE);

    if ($this->isCiContext() || $this->isLocalDevMode()) {
      $projectRoot = $this->getDockerMountSource(getenv('CI_PROJECT_DIR'));
    }
    else {
      $projectRoot = getcwd();
    }
    $php = $this->config->readValue('php');
    $traefik = $this->config->readValue('traefik');

    // Check if SSH auth sockets are supported.
    $ssh_auth_sock = getenv('SSH_AUTH_SOCK');
    $php['ssh'] = !empty($ssh_auth_sock);
    if ($php['ssh']) {
      $php['ssh_auth_sock'] = ($this->isCiContext() || $this->isLocalDevMode()) ?
        $this->getDockerMountSource('/ssh-agent') :
        '$SSH_AUTH_SOCK';
    }
    $this->config->setValue('projectroot', $projectRoot, FALSE);
    $this->config->setValue('projectrootfiles', $projectRoot, FALSE);
    $this->config->setValue('projectrootinvoiceninja', $projectRoot . '/in', FALSE);
    $this->config->setValue('projectdomain', str_replace('_', '-', $this->config->readValue('projectname')) . '.' . $traefik['domain'], FALSE);
    $this->config->setValue('projectprotocol', 'http' . ($traefik['usessl'] ? 's' : ''), FALSE);
    $this->config->setValue('socketprotocol', 'ws' . ($traefik['usessl'] ? 's' : ''), FALSE);
    $projectport = '';
    if ($traefik['usessl'] && (int) $traefik['ports'] !== 443) {
      $projectport = ':' . $traefik['ports'];
    elseif (!$traefik['usessl'] && (int) $traefik['port'] !== 80) {
      $projectport = ':' . $traefik['port'];
    $this->config->setValue('projectport', $projectport, FALSE);
    $relatedprojectdomains = [];
    foreach ($php['related_subdomains'] as $related_subdomain) {
      $relatedprojectdomains[] = $related_subdomain . '.' . $traefik['domain'];
    }
    $this->config->setValue('relatedprojectdomains', $relatedprojectdomains, FALSE);
    if (!empty($relatedprojectdomains)) {
    $this->config->setValue('php', $php, FALSE);
    $docker_group_id = trim(shell_exec('stat -c "%g" /var/run/docker.sock'));
    $this->config->setValue('docker_group_id', $docker_group_id, FALSE);
    if ($alerta_api_key = getenv('ALERTA_APIKEY')) {
      $alerta = [
        'apikey' => $alerta_api_key,
      ];
      if ($value = getenv('ALERTA_ENVIRONMENT')) {
        $alerta['environment'] = $value;
      }
      if ($value = getenv('ALERTA_PROJECT_ID')) {
        $alerta['project_id'] = $value;
      }
      $this->config->setValue('alerta', $alerta, FALSE);
    }

    // Turn off basic auth in local dev environment.
    if ($this->isLocalDevMode()) {
      $this->config->setValue('basicauth', ['enable' => FALSE], FALSE);
    }
  /**
   * Update Drupal Project for Docker.
   */
  public function updateProject(): void {

    // We only do the fancy stuff for developers.
    if (!$this->isDevMode()) {
      return;
    }

    $this->io->info('You may have to update your Docker4Drupal environment by running "composer lakedrops:docker4drupal".');
  }

jurgenhaas's avatar
jurgenhaas committed
  /**
   * Configure Drupal Project for Docker.
   */
  public function configureProject(): void {
jurgenhaas's avatar
jurgenhaas committed

jurgenhaas's avatar
jurgenhaas committed
    // We only do the fancy stuff for developers.
    if (!$this->isDevMode()) {
jurgenhaas's avatar
jurgenhaas committed
      return;
    }

    // Configure Drupal environment if avaiable.
    if ($this->getPackage('lakedrops/drupal-environment')) {
      $handler = new DrupalEnvironment($this->composer, $this->io);
      $handler->setupLakeDropsProject();

      // Update config for production build.
      if (getenv('LAKEDROPS_BUILD_NG') === 'yes') {
        $config = $handler->getConfig();
jurgenhaas's avatar
jurgenhaas committed
        $isStaging = !in_array(getenv('CI_COMMIT_REF_SLUG'), ['master', 'main'], TRUE);
        $root = '/drupal/' . getenv('CI_PROJECT_ID') . '/' . getenv('CI_COMMIT_BRANCH');
        $drupal = $this->config->readValue('drupal');
        $drupal['live'] = $config->readValue('live');
        $traefik = $this->config->readValue('traefik');
        $traefik['usessl'] = 1;
        $traefik['ports'] = 443;
        $crontabs = $this->config->readValue('crontabs');
jurgenhaas's avatar
jurgenhaas committed
        $crontabs['enable'] = (array_sum(array_map('count', $crontabs)) > 0);
          if ($this->config->readValue(['backup', 'enable'])) {
            $crontabs['borgmatic']['Backup'] = [
              'schedule' => $this->config->readValue(['backup', 'crontime']),
              'command' => 'backup',
            ];
            $crontabs['borgmatic']['Check backup'] = [
              'schedule' => $this->config->readValue(['backup', 'crontimecheck']),
              'command' => 'check',
            ];
          }
          $crontabs['www-data']['MySQL backup'] = [
            'schedule' => '5 0 * * *',
            'command' => 'cd /var/www/html && /var/www/html/vendor/bin/drush sql:dump --result-file=/var/backups/mysql/drupal.sql',
jurgenhaas's avatar
jurgenhaas committed
          $crontabs['enable'] = TRUE;
jurgenhaas's avatar
jurgenhaas committed
          $crontabs['enable_mysql_backup'] = TRUE;
        $this->config->setValue('crontabs', $crontabs, FALSE);
jurgenhaas's avatar
jurgenhaas committed
        $overwriteConfig = [
jurgenhaas's avatar
jurgenhaas committed
          'docker0' => [
            'ip' => 'TRAEFIK-IP-PLACEHOLDER',
            'proxy' => 'TRAEFIK-IP-PLACEHOLDER',
          ],
          'drupal' => $drupal,
          'traefik' => $traefik,
          'projectroot' => $root . '/app',
jurgenhaas's avatar
jurgenhaas committed
          'projectrootbackup' => $root . '/backup',
          'projectrootdb' => $root . '/db',
          'projectrootfiles' => $root . '/files',
jurgenhaas's avatar
jurgenhaas committed
          'projectrootredis' => $root . '/redis',
          'projectrootinvoiceninja' => $root . '/in',
          'projectname' => 'drupal_' . getenv('PROJECT_NAME') . '_' . getenv('CI_COMMIT_REF_SLUG'),
          'projectdomain' => str_replace('_', '-', $this->config->readValue('domain') ?? ''),
          'projectprotocol' => 'https',
          'projectport' => '',
          'socketprotocol' => 'wss',
jurgenhaas's avatar
jurgenhaas committed
          'extradomains' => $this->config->readValue('aliases') ?? [],
jurgenhaas's avatar
jurgenhaas committed
        foreach ($overwriteConfig as $key => $value) {
          $this->config->setValue($key, $value, FALSE);
        }
      }
    }

jurgenhaas's avatar
jurgenhaas committed
    $fs = new Filesystem();
    $installationManager = $this->composer->getInstallationManager();

    $webRoot = $this->config->readValue('webroot');
    if ($webRoot !== NULL) {
      if (!$fs->exists($webRoot)) {
        return;
      }
    }
    else {
      $drupalCorePackage = $this->getDrupalCorePackage();
      if (!$drupalCorePackage) {
        // We are called too early, Drupal core is not available yet.
        return;
      }
      $corePath = $installationManager->getInstallPath($drupalCorePackage);
jurgenhaas's avatar
jurgenhaas committed
      // Directory where Drupal's index.php is located.
      $webRoot = basename(dirname($corePath));
jurgenhaas's avatar
Loading
Loading full blame...