Verified Commit 592601b0 authored by Hephaestus Builder's avatar Hephaestus Builder
Browse files

FIX: key deletion strict type violation (Database\MySQL)

REM: walkback migration changes for next release (CLI\Transfer)
parent 5461c156
#!/usr/bin/env apnscp_php
<?php declare(strict_types=1);
/**
* Copyright (C) Apis Networks, Inc - All Rights Reserved.
*
* Unauthorized copying of this file, via any medium, is
* strictly prohibited without consent. Any dissemination of
* material herein is prohibited.
*
* For licensing inquiries email <licensing@apisnetworks.com>
*
* Written by Matt Saladna <matt@apisnetworks.com>, May 2017
*/
use CLI\Transfer\CliParser;
ini_set('default_socket_timeout', "180");
<?php
/**
* Copyright (C) Apis Networks, Inc - All Rights Reserved.
*
* Unauthorized copying of this file, via any medium, is
* strictly prohibited without consent. Any dissemination of
* material herein is prohibited.
*
* For licensing inquiries email <licensing@apisnetworks.com>
*
* Written by Matt Saladna <matt@apisnetworks.com>, May 2017
*/
ini_set('default_socket_timeout', 180);
error_reporting(E_ALL);
define('INCLUDE_PATH', dirname(__DIR__, 2));
include(INCLUDE_PATH.'/lib/CLI/cmd.php');
include(INCLUDE_PATH.'/lib/CLI/Transfer.php');
define('ADMIN_API_KEY', get_admin_key());
function get_admin_key() {
function get_admin_key() {
$mockup = \Auth::context(null);
$api = \apnscpFunctionInterceptor::factory($mockup);
$keys = $api->auth_get_api_keys();
......@@ -31,51 +27,190 @@
}
return array_get(array_pop($keys), 'key', null);
}
function dump_log() {
$buffer = Error_Reporter::get_buffer();
if (empty($buffer))
return false;
foreach ($buffer as $err) {
if (!$err['severity'] & Error_Reporter::E_ERROR)
continue;
fwrite(STDERR, $err['message']."\n");
}
foreach ($buffer as $b) {
$msg = strtoupper(Error_Reporter::error_type($b['severity']))
. ': ' . $b['message'];
dlog($msg);
// picked up automatically
if ($b['severity']&Error_Reporter::E_ERROR)
continue;
if ($b['severity']&Error_Reporter::E_WARNING)
fwrite(STDERR, $msg . "\n");
else
fwrite(STDOUT, $msg . "\n");
}
}
function usage() {
echo "usage: " . basename($_SERVER['argv'][0]) . " [-s server] <domain>" . "\n" . "\n";
echo " -f, --force\t\t Force stage 1 -> 2 migration ahead of 24 hour sanity check" . "\n" .
" -s, --server\t\t Set target server (applicable in stage 0 only)" . "\n" .
" -t, --template\t\t Specify e-mail template for stage 1 notice" . "\n" .
" --stage\t\t Force creation stage (0, 1, 2)" . "\n" .
" --do\t\t Perform a single stage of migration \",\" delimits optional arguments. May be specified multiple times". "\n".
" --components\t List migration stage components" . "\n" .
" -o --override\t\t Alter configuration on new server (first stage only)" . "\n" .
" -p --pull\t\t Target server is source, this server is destination." . "\n" .
" --no-create\t Skip account creation on target server" . "\n" .
" --no-suspend\t Disable automatic suspension following migration" . "\n";
exit(1);
}
[$options, $sites] = array_values(CliParser::parse());
function list_components() {
echo "Available components to migrate:\n";
$rfxn = new ReflectionClass('CLI_Transfer');
foreach ($rfxn->getMethods() as $method) {
if (0 !== strpos($method->getName(), "_sync_")) {
continue;
}
echo "\t" . substr($method->getName(), "6"), "\n";
}
exit(1);
}
if (!$sites) {
CliParser::usage();
$server = $template = null;
$shortopts = "s:t:c:o:fph";
$longopts = array('force', 'help', 'pull', 'override:', 'stage:', 'template:', 'server:', 'components', 'no-create', 'no-suspend', 'do:');
$ind = null;
$opts = getopt($shortopts, $longopts, $ind);
$argv = $_SERVER['argv'];
$override = [];
// @TODO support longopts
foreach( $opts as $o => $a ) {
if ($o === "h" || $o === "help") {
usage();
} else if ($o === "components") {
list_components();
} else if ($o === "override" || $o === "o" || $o === 'c') {
if ($o === 'override' || $o === 'o') {
deprecated("Use -c option instead of %s", $o);
}
foreach (array_map('\Opcenter\CliParser::parseServiceConfiguration', (array)$a) as $opt) {
$key = key($opt);
$config = array_pop($opt);
if (!isset($override[$key])) {
$override[$key] = [];
}
$override[$key] = array_replace($override[$key], $config);
}
}
while($k = array_search( "-" . $o, $argv, true)) {
if ($k) {
unset($argv[$k]);
}
if (preg_match( "/^.*".$o.":.*$/i", $shortopts )) {
unset($argv[$k+1]);
}
}
}
$argv = array_slice($_SERVER['argv'], $ind);
$argc = count($argv);
if ($argc < 1) {
usage();
}
// translate $domain to domain if site id given
if (count($argv) > 1) {
info("Multiple domains found, enumerating list");
}
$sites = array_flatten(array_map(function ($d) {
if ('site' === ($site = 'site' . \Auth::get_site_id_from_anything($d))) {
// not found
$sites = array_map(function ($d) {
return 'site' . $d;
}, (array)\Auth::get_site_id_from_invoice($d));
if (!$sites) {
warn("No sites found matching `%s'", $d);
return [];
}
return array_unique((array)array_first($sites, function ($site) {
return (new \Opcenter\SiteConfiguration($site))->
getServiceValue('billing', 'invoice', false);
}) + append_config($sites));
}
return $site;
}, $argv));
if (!$sites) {
usage();
} else if (count($sites) > 1) {
foreach ($sites as $s) {
$domain = \Auth::get_domain_from_site_id(substr($s, 4));
if (null === $domain) {
fatal("Unable to find matching domain for `%s'", $s);
}
info("- %s (%s)", $domain, $s);
}
}
if (isset($opts['server'])) {
$server = $opts['server'];
} else if (isset($opts['s'])) {
$server = $opts['s'];
}
if (isset($opts['template'])) {
$template = $opts['template'];
} else if (isset($opts['t'])) {
$template = $opts['t'];
}
if ($template && !file_exists($template)) {
fatal("specified template `%s' does not exist", $template);
}
if (isset($opts['override'])) {
}
// admin just needs remote API access vb
$stage = null;
if (isset($opts['stage'])) {
$stage = $opts['stage'];
}
foreach ($sites as $site) {
$domain = \Auth::get_domain_from_site_id(substr($site, 4));
$_ENV['DOMAIN'] = $domain;
if (null === ($ctx = \Auth::nullableContext(null, $site))) {
dlog("Skipping %s - error on initializing context", $site);
continue;
}
$xfer = CLI_Transfer::instantiateContexted($ctx, [$options]);
if ($options['override']) {
$xfer->setOverrides($options['override']);
$xfer = new CLI_Transfer(Auth::context(null, $domain));
if ($override) {
$xfer->setOverrides($override);
}
if (!$options['create']) {
if (isset($opts['no-create'])) {
dlog("Skipping domain creation");
$xfer->skipCreateDomain();
}
if ($options['force']) {
if (isset($opts['force']) || isset($opts['f'])) {
dlog("Forcing migration ahead of 24 hour sanity check");
$xfer->force();
}
if (!is_null($options['stage'])) {
dlog("Setting migration stage `%d'", $options['stage']);
$xfer->setStage($options['stage']);
if (!is_null($stage)) {
$stage = intval($stage);
dlog("Setting migration stage `%d'", $stage);
$xfer->setStage($stage);
}
if ($options['server']) {
dlog("Setting server `%s'", $options['server']);
$xfer->setTargetServer($options['server']);
if ($server) {
dlog("Setting server `%s'", $server);
$xfer->setTargetServer($server);
}
if ($options['do']) {
foreach ((array)$options['do'] as $what) {
if (isset($opts['do'])) {
foreach ((array)$opts['do'] as $what) {
$args = array();
$args = explode(",", $what, 2);
$what = array_shift($args);
$args = $args ? \Opcenter\CliParser::parseArgs($args[0]) : null;
......@@ -83,29 +218,12 @@
}
}
if ($options['pull']) {
if (!empty($opts['pull']) || !empty($opts['p'])) {
$xfer->flip();
}
if (!isset($options['no-suspend']) && !$xfer->suspend()) {
warn("Error on suspending %s", $domain);
}
// second stage
if ($options['notify'] && !$xfer->notify() && CLI_Transfer::STATUS_EMAIL) {
Mail::send(
CLI_Transfer::STATUS_EMAIL,
"Migration Notification Failed - " . $domain,
join("\n", Error_Reporter::get_errors()),
"From: " . Crm_Module::FROM_NAME . " <" . Crm_Module::FROM_ADDRESS . ">"
);
}
if ($options['log']) {
(new \CLI\Output('line'))->setDescriptor(\CLI\Output::STDOUT)->fromLog(\Error_Reporter::flush_buffer())->echo("DONE");
}
exit(0);
try {
$initialStage = $xfer->migrationStage();
$originalstage = $xfer->get_migration_stage();
$xfer->process();
} catch (Exception $e) {
$reason = $e->getMessage();
......@@ -113,26 +231,42 @@
$reason .= " - update domain auth table?";
}
Mail::send(
CLI_Transfer::STATUS_EMAIL,
"Migration Error (EX) - " . $domain,
"Reason: " . $reason . "\n" . Error_Reporter::parse_debug_bt(0, -1, $e->getTrace()) .
"\n\n" . var_export(Error_Reporter::get_buffer(), true),
"From: " . Crm_Module::FROM_NAME . " <" . Crm_Module::FROM_ADDRESS . ">"
);
error("migration failed - unhandled exception");
}
dump_log();
dlog("Transfer %s (%s) %s",
$domain,
Error_Reporter::error_type(Error_Reporter::get_severity()),
Error_Reporter::is_error() ? 'Failed' : 'Succeeded'
);
$stage = $xfer->get_migration_stage();
$currentStage = $xfer->migrationStage();
if ($xfer->incomplete()) {
error("Error encountered during %s migration. Migration is incomplete!", $domain);
} else if ($xfer->migrated()) {
if (!isset($options['no-suspend']) && !$xfer->suspend()) {
if (Error_Reporter::is_error()) {
if (!is_debug()) {
Mail::send(
CLI_Transfer::STATUS_EMAIL,
"Migration Error - " . $domain,
join("\n", Error_Reporter::get_errors()),
"From: " . Crm_Module::FROM_NAME . " <" . Crm_Module::FROM_ADDRESS . ">"
);
} else {
error("Error encountered during %s migration. Migration is incomplete!", $domain);
}
} else if ($xfer->finished()) {
if (!isset($opts['no-suspend']) && !$xfer->suspend()) {
warn("Error on suspending %s", $domain);
}
// second stage
if ($options['notify'] && !$xfer->notify() && CLI_Transfer::STATUS_EMAIL)
{
if (!$xfer->notify()) {
Mail::send(
CLI_Transfer::STATUS_EMAIL,
"Migration Notification Failed - " . $domain,
......@@ -142,11 +276,67 @@
}
}
\Error_Reporter::print_buffer();
// @TODO move to _migrate hook?
foreach ([$xfer->getTargetServer(), null] as $adminServer) {
$adminAPI = Util_API::create_client(ADMIN_API_KEY, $adminServer);
try {
$adminAPI->common_whoami();
} catch (SoapFault $e) {
continue;
}
}
if ($adminAPI->crm_configured() && ($originalstage < $stage) && $stage == 1 && $template/* initial */) {
// first stage
// open a ticket to notify
$sid = $adminAPI->crm_get_id_by_subject('Server Migration');
if ($sid < 1) {
$sid = $adminAPI->crm_get_id_by_subject('Supervisor'); // fallback
}
$body = file_get_contents($template);
if ($options['log']) {
(new \CLI\Output('line'))->setDescriptor(\CLI\Output::STDOUT)->fromLog(\Error_Reporter::flush_buffer())->echo("DONE");
// let's do some simple string substitution,
$search = array(
'%{DESTINATION_SERVER}',
'%{DESTINATION_SERVER_SHORT}',
'%{SOURCE_SERVER}',
'%{SOURCE_SERVER_SHORT}',
'%{DESTINATION_IP}'
);
$replace = array(
$server . substr(SERVER_NAME, strlen(SERVER_NAME_SHORT)),
$server,
SERVER_NAME,
SERVER_NAME_SHORT,
$xfer->getRemoteIP()
);
$body = str_replace($search, $replace, $body);
//$adminemail = $adminAPI->admin_get_meta_from_domain($domain, 'siteinfo', 'email');
// adding attachments after filing ticket, don't e-mail just yet!
$opts = array(
'state' => 'new',
'email' => true,
);
$id = $adminAPI->crm_file_new_trouble_ticket($domain, $sid);
$attachments = array();
$attachments[] = array(
'content' => join("\r\n", $xfer->getBuffer()),
'name' => 'migration-stage-1-log.txt',
);
$rid = $adminAPI->crm_append_trouble_ticket($id, $body, $opts, $attachments);
if ($id < 1) {
Mail::send(
CLI_Transfer::STATUS_EMAIL,
"Migration Notification Error - " . $domain,
join("\n", Error_Reporter::get_errors()),
"From: " . Crm_Module::FROM_NAME . " <" . Crm_Module::FROM_ADDRESS . ">"
);
}
}
}
......
This diff is collapsed.
......@@ -36,7 +36,7 @@
const VERSION_CHECK_URL = 'https://api.wordpress.org/core/version-check/1.7/';
const PLUGIN_VERSION_CHECK_URL = 'https://api.wordpress.org/plugins/info/1.0/%plugin%.json';
const THEME_VERSION_CHECK_URL = 'https://api.wordpress.org/themes/info/1.2/?action=theme_information&request[slug]=%theme%&request[fields][versions]=1';
const DEFAULT_VERSION_LOCK = 'major';
const DEFAULT_VERSION_LOCK = 'none';
protected $aclList = array(
'min' => array(
......
......@@ -671,7 +671,12 @@
string $val = null,
string $group = 'client'
): bool {
Map::load($path, 'cd', 'inifile')->quoted(true)->section($group)[$field] = $val;
$map = Map::load($path, 'cd', 'inifile')->quoted(true)->section($group);
if (null === $val) {
$map->delete($field);
} else {
$map->set($field, $val);
}
return chmod($path, 0600);
......
......@@ -184,7 +184,7 @@
* @param string $group
* @return bool
*/
public function set_option($option, $value = null, $group = 'client')
public function set_option(string $option, string $value = null, string $group = 'client')
{
if (!IS_CLI) {
return $this->query('mysql_set_option', $option, $value, $group);
......
# Migration play
# vim:et ts=2 sw=2 sts=2 syntax=yaml filetype=yaml
---
- block:
# Add tasks
- fail: msg="Remove me - migration step UP"
tags: ['up']
- block:
# Add tasks
- fail: msg="Remove me - migration step DOWN"
tags: ['down']
\ No newline at end of file
......@@ -62,7 +62,7 @@ class SoapTest extends TestFramework {
$keys = $afi->auth_get_api_keys();
if (!$keys) {
$key = $afi->auth_create_api_key();
defer($_, static function () use ($key, $afi) {
register_shutdown_function(static function () use ($key, $afi) {
$afi->auth_delete_api_key($key);
});
} else {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment