You are here

replication.drush.inc in Replication 8

Same filename and directory in other branches
  1. 8.2 replication.drush.inc

Drush integration for the replication module.

File

replication.drush.inc
View source
<?php

/**
 * @file
 * Drush integration for the replication module.
 */

// @todo move this file to the Relaxed module or revise to not be dependent
// upon Relaxed.
use Doctrine\CouchDB\CouchDBClient;
use Psr\Log\LogLevel;
use Relaxed\Replicator\ReplicationTask;
use Relaxed\Replicator\Replication;

/**
 * Implements of hook_drush_command().
 */
function replication_drush_command() {
  $items = [];
  $items['replication-uninstall'] = [
    'bootstrap' => DRUSH_BOOTSTRAP_NONE,
    'description' => 'Uninstall Replication.',
    'aliases' => [
      'repun',
    ],
  ];
  $items['replication-start'] = [
    'bootstrap' => DRUSH_BOOTSTRAP_NONE,
    'description' => 'Start a replication.',
    'arguments' => [
      'source' => dt('Source database.'),
      'target' => dt('Target database.'),
    ],
    'required-arguments' => TRUE,
    'options' => [
      'continuous' => [
        'description' => dt('Continuous replication.'),
        'default' => FALSE,
      ],
      'replicator' => [
        'description' => dt('The used replicator.'),
      ],
    ],
    'outputformat' => [
      'default' => 'key-value',
      'pipe-format' => 'json',
      'field-labels' => [
        'ok' => 'Status',
        'no_changes' => 'No changes',
        'session_id' => 'Session ID',
        'source_last_seq' => 'Last sequence number',
        'replication_id_version' => 'Replication protocol version',
      ],
      'output-data-type' => 'format-list',
    ],
  ];
  $items['replication-stop'] = [
    'bootstrap' => DRUSH_BOOTSTRAP_NONE,
    'description' => 'Stop a replication.',
    'arguments' => [
      'source' => dt('Source database.'),
      'target' => dt('Target database.'),
    ],
    'required-arguments' => TRUE,
    'options' => [
      'continuous' => [
        'description' => dt('Continuous replication.'),
        'default' => FALSE,
      ],
      'replicator' => [
        'description' => dt('The used replicator.'),
      ],
    ],
    'outputformat' => [
      'default' => 'key-value',
      'pipe-format' => 'json',
      'field-labels' => [
        'ok' => 'Status',
        'no_changes' => 'No changes',
        'session_id' => 'Session ID',
        'source_last_seq' => 'Last sequence number',
        'replication_id_version' => 'Replication protocol version',
      ],
      'output-data-type' => 'format-list',
    ],
  ];
  $items['replication-active'] = [
    'bootstrap' => DRUSH_BOOTSTRAP_NONE,
    'description' => 'Prints information about the specific active replication between target and source databases.',
    'arguments' => [
      'source' => dt('Source database.'),
      'target' => dt('Target database.'),
    ],
    'options' => [
      'replicator' => [
        'description' => dt('The used replicator.'),
      ],
    ],
    'outputformat' => [
      'default' => 'key-value-list',
      'pipe-format' => 'json',
      'field-labels' => [
        'source' => 'Source',
        'target' => 'Target',
        'started_on' => 'Started on',
        'progress' => 'Progress',
        'docs_read' => 'Documents read',
        'docs_written' => 'Documents written',
        'revisions_checked' => 'Revisions checked',
        'doc_write_failures' => 'Write failures',
        'pid' => 'Process ID',
      ],
    ],
  ];
  return $items;
}

/**
 * Implements drush_hook_COMMAND().
 */
function drush_replication_uninstall() {
  $extension = 'replication';
  $uninstall = TRUE;
  $extension_info = drush_get_extensions();
  $required = drush_drupal_required_modules($extension_info);
  if (in_array($extension, $required)) {
    $info = $extension_info[$extension]->info;
    $explanation = !empty($info['explanation']) ? ' ' . dt('Reason: !explanation.', [
      '!explanation' => strip_tags($info['explanation']),
    ]) : '';
    drush_log(dt('!extension is a required extension and can\'t be uninstalled.', [
      '!extension' => $extension,
    ]) . $explanation, LogLevel::INFO);
    $uninstall = FALSE;
  }
  elseif (!$extension_info[$extension]->status) {
    drush_log(dt('!extension is already uninstalled.', [
      '!extension' => $extension,
    ]), LogLevel::INFO);
    $uninstall = FALSE;
  }
  elseif (drush_extension_get_type($extension_info[$extension]) == 'module') {
    $dependents = [];
    foreach (drush_module_dependents([
      $extension,
    ], $extension_info) as $dependent) {
      if (!in_array($dependent, $required) && $extension_info[$dependent]->status) {
        $dependents[] = $dependent;
      }
    }
    if (count($dependents)) {
      drush_log(dt('To uninstall !extension, the following extensions must be uninstalled first: !required', [
        '!extension' => $extension,
        '!required' => implode(', ', $dependents),
      ]), LogLevel::ERROR);
      $uninstall = FALSE;
    }
  }
  if ($uninstall) {
    drush_print(dt('Replication will be uninstalled.'));
    if (!drush_confirm(dt('Do you really want to continue?'))) {
      return drush_user_abort();
    }
    try {

      // Delete all replication_log entities.
      $storage = \Drupal::entityTypeManager()
        ->getStorage('replication_log')
        ->getOriginalStorage();
      $entities = $storage
        ->loadMultiple();
      $storage
        ->delete($entities);
      drush_module_uninstall([
        $extension,
      ]);
    } catch (Exception $e) {
      drush_log($e
        ->getMessage(), LogLevel::ERROR);
    }

    // Inform the user of final status.
    drush_log(dt('!extension was successfully uninstalled.', [
      '!extension' => $extension,
    ]), LogLevel::INFO);
  }
}

/**
 * Implements drush_hook_COMMAND_validate().
 */
function drush_replication_start_validate() {

  // Array of "Callback arguments" and "command line args".
  $params = func_get_args();
  replication_command_validate($params);
}

/**
 * Implements drush_hook_COMMAND_validate().
 */
function drush_replication_stop_validate() {

  // Array of "Callback arguments" and "command line args".
  $params = func_get_args();
  replication_command_validate($params);
}

/**
 * Implements drush_hook_COMMAND_validate().
 */
function drush_replication_active_validate() {

  // Array of "Callback arguments" and "command line args".
  $params = func_get_args();
  if (isset($params[0]) || isset($params[1])) {
    replication_command_validate($params);
  }
}

/**
 * Implements drush_hook_COMMAND().
 */
function drush_replication_start($source, $target) {
  try {
    $source_client = replication_client_factory($source);
    $target_client = replication_client_factory($target);

    // Create the replication task.
    $task = new ReplicationTask();

    // Create the replication.
    $replication = new Replication($source_client, $target_client, $task);

    // Generate and set a replication ID.
    $replication->task
      ->setRepId($replication
      ->generateReplicationId());

    // Start the replication.
    $replicationResult = $replication
      ->start();
    return $replicationResult;
  } catch (\Exception $e) {
    drush_set_error($e
      ->getMessage());
  }
}

/**
 * Implements drush_hook_COMMAND().
 */
function drush_replication_stop($source, $target) {
  try {
    $client = replication_client_factory();
    $continuous = drush_get_option('continuous');
    return $client
      ->replicate($source, $target, TRUE, $continuous);
  } catch (\Exception $e) {
    drush_set_error($e
      ->getMessage());
  }
}

/**
 * Implements drush_hook_COMMAND().
 *
 * Prints information about the specific active replication between target and
 * source databases.
 */
function drush_replication_active($source = NULL, $target = NULL) {
  try {
    $client = replication_client_factory();
    $results = $client
      ->getActiveTasks();
    foreach ($results as $key => $result) {
      $results[$key]['started_on'] = date('D, j M Y, H:i:s e', $result['started_on']);
      if ($source && $target && is_array($results)) {
        $source_diff = array_diff(replication_get_url_parts($result['source']), replication_get_url_parts($source));
        $target_diff = array_diff(replication_get_url_parts($result['target']), replication_get_url_parts($target));
        if (empty($source_diff) && empty($target_diff)) {

          // Return information about one active replication.
          return [
            $results[$key],
          ];
        }
        else {
          drush_print('No active replication.');
          return;
        }
      }
    }
    if (!empty($results)) {

      // Return information about all active replications.
      return $results;
    }
    else {
      drush_print('No active replications.');
    }
  } catch (\Exception $e) {
    drush_set_error($e
      ->getMessage());
  }
}

/**
 * Helper function for command validation.
 *
 * @param $params
 */
function replication_command_validate($params) {
  if (replication_get_http_response_code($params['0']) != 200) {
    drush_set_error(dt('Source database not found.'));
  }
  if (replication_get_http_response_code($params['1']) != 200) {
    drush_set_error(dt('Target database not found.'));
  }
}

/**
 * Returns the CouchDBClient() object.
 */
function replication_client_factory($url) {
  return CouchDBClient::create([
    'url' => (string) $url,
    'timeout' => 10,
  ]);
}

/**
 * Returns the response code for a request.
 *
 * @param $url
 *
 * @return string
 */
function replication_get_http_response_code($url) {
  $ch = curl_init($url);
  curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  curl_exec($ch);
  $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  curl_close($ch);
  return $httpcode;
}

/**
 * Returns url parts (host, port, path, user and pass).
 *
 * @param $url
 * @param bool $credentials
 *
 * @return array
 */
function replication_get_url_parts($url, $credentials = FALSE) {
  $url_parts = parse_url($url);
  $options = [
    'host' => $url_parts['host'],
    'port' => $url_parts['port'],
  ];
  $path = trim($url_parts['path'], '/');
  if ($path != '') {
    $options['path'] = $path;
  }
  if ($credentials) {
    $options['user'] = $url_parts['user'] ? $url_parts['user'] : NULL;
    $options['password'] = $url_parts['pass'] ? $url_parts['pass'] : NULL;
  }
  return $options;
}

Functions

Namesort descending Description
drush_replication_active Implements drush_hook_COMMAND().
drush_replication_active_validate Implements drush_hook_COMMAND_validate().
drush_replication_start Implements drush_hook_COMMAND().
drush_replication_start_validate Implements drush_hook_COMMAND_validate().
drush_replication_stop Implements drush_hook_COMMAND().
drush_replication_stop_validate Implements drush_hook_COMMAND_validate().
drush_replication_uninstall Implements drush_hook_COMMAND().
replication_client_factory Returns the CouchDBClient() object.
replication_command_validate Helper function for command validation.
replication_drush_command Implements of hook_drush_command().
replication_get_http_response_code Returns the response code for a request.
replication_get_url_parts Returns url parts (host, port, path, user and pass).