mirror of
https://github.com/moodle/moodle.git
synced 2025-04-15 13:33:52 +02:00
MDL-65471 upgrade: framework to reduce maintenance mode
This commit is contained in:
parent
fba0658777
commit
027c770eab
@ -48,12 +48,16 @@ require_once($CFG->libdir.'/environmentlib.php');
|
||||
$lang = isset($SESSION->lang) ? $SESSION->lang : $CFG->lang;
|
||||
list($options, $unrecognized) = cli_get_params(
|
||||
array(
|
||||
'non-interactive' => false,
|
||||
'allow-unstable' => false,
|
||||
'help' => false,
|
||||
'lang' => $lang,
|
||||
'verbose-settings' => false,
|
||||
'is-pending' => false,
|
||||
'allow-unstable' => false,
|
||||
'help' => false,
|
||||
'is-maintenance-required' => false,
|
||||
'is-pending' => false,
|
||||
'lang' => $lang,
|
||||
'maintenance' => true,
|
||||
'non-interactive' => false,
|
||||
'set-ui-upgrade-lock' => false,
|
||||
'unset-ui-upgrade-lock' => false,
|
||||
'verbose-settings' => false,
|
||||
),
|
||||
array(
|
||||
'h' => 'help'
|
||||
@ -79,19 +83,35 @@ Please note you must execute this script with the same uid as apache!
|
||||
Site defaults may be changed via local/defaults.php.
|
||||
|
||||
Options:
|
||||
--non-interactive No interactive questions or confirmations
|
||||
--allow-unstable Upgrade even if the version is not marked as stable yet,
|
||||
required in non-interactive mode.
|
||||
--lang=CODE Set preferred language for CLI output. Defaults to the
|
||||
site language if not set. Defaults to 'en' if the lang
|
||||
parameter is invalid or if the language pack is not
|
||||
installed.
|
||||
--verbose-settings Show new settings values. By default only the name of
|
||||
new core or plugin settings are displayed. This option
|
||||
outputs the new values as well as the setting name.
|
||||
--is-pending If an upgrade is needed it exits with an error code of
|
||||
2 so it distinct from other types of errors.
|
||||
-h, --help Print out this help
|
||||
--allow-unstable Upgrade even if the version is not marked as stable yet,
|
||||
required in non-interactive mode.
|
||||
-h, --help Print out this help.
|
||||
--is-maintenance-required Returns exit code 2 if the upgrade requires maintenance mode.
|
||||
Returns exit code 3 if no maintenance is required for the upgrade.
|
||||
--is-pending Exit with error code 2 if an upgrade is required.
|
||||
--lang=CODE Set preferred language for CLI output. Defaults to the
|
||||
site language if not set. Defaults to 'en' if the lang
|
||||
parameter is invalid or if the language pack is not
|
||||
installed.
|
||||
--maintenance Sets whether this upgrade will use maintenance mode.
|
||||
If not possible, the upgrade will not happen and the script will exit.
|
||||
WARNING: Caches (except theme) will be STALE and MUST be purged after upgrading.
|
||||
DO NOT USE if the upgrade contains known breaking changes to the way data
|
||||
and the database interact.
|
||||
RECOMMENDED for lightweight deployments, to allow for a graceful purge and
|
||||
rebuild of the cache.
|
||||
--non-interactive No interactive questions or confirmations.
|
||||
--set-ui-upgrade-lock Sets the upgrade to CLI only and unable to be triggered from the frontend.
|
||||
If called with --maintenance=false, the lock WILL NOT be released when the
|
||||
upgrade finishes, and MUST be manually removed.
|
||||
If called with --is-maintenance-required before an upgrade,
|
||||
The lock WILL be released when the upgrade finishes.
|
||||
--unset-ui-upgrade-lock Removes the frontend upgrade lock, if the lock exists.
|
||||
Useful when an error during the upgrade leaves the upgrade locked,
|
||||
or there is need to control the time where the unlock happens.
|
||||
--verbose-settings Show new settings values. By default only the name of
|
||||
new core or plugin settings are displayed. This option
|
||||
outputs the new values as well as the setting name.
|
||||
|
||||
Example:
|
||||
\$sudo -u www-data /usr/bin/php admin/cli/upgrade.php
|
||||
@ -115,12 +135,58 @@ if ($version < $CFG->version) {
|
||||
$oldversion = "$CFG->release ($CFG->version)";
|
||||
$newversion = "$release ($version)";
|
||||
|
||||
if (!moodle_needs_upgrading()) {
|
||||
if ($options['unset-ui-upgrade-lock']) {
|
||||
// Unconditionally unset this config if requested.
|
||||
set_config('outagelessupgrade', false);
|
||||
cli_writeln(get_string('cliupgradeunsetlock', 'admin'));
|
||||
}
|
||||
|
||||
$allhash = core_component::get_all_component_hash();
|
||||
|
||||
// Initialise allcomponent hash if not set. It will be correctly set after upgrade.
|
||||
$CFG->allcomponenthash = $CFG->allcomponenthash ?? '';
|
||||
if (!$options['maintenance']) {
|
||||
if ($allhash !== $CFG->allcomponenthash) {
|
||||
// Throw an error here, we can't proceed, this needs to set maintenance.
|
||||
cli_error(get_string('cliupgrademaintenancerequired', 'core_admin'), 2);
|
||||
}
|
||||
|
||||
// Set a constant to stop any upgrade var from being set during processing.
|
||||
// This protects against the upgrade setting timeouts and maintenance during the upgrade.
|
||||
define('CLI_UPGRADE_RUNNING', true);
|
||||
|
||||
// This database control is the control to block the GUI from doing upgrade related actions.
|
||||
set_config('outagelessupgrade', true);
|
||||
}
|
||||
|
||||
// We should ignore all upgrade locks here.
|
||||
if (!moodle_needs_upgrading(false)) {
|
||||
cli_error(get_string('cliupgradenoneed', 'core_admin', $newversion), 0);
|
||||
}
|
||||
|
||||
if ($options['is-pending']) {
|
||||
cli_error(get_string('cliupgradepending', 'core_admin'), 2);
|
||||
// Handle exit based options for outputting upgrade state.
|
||||
if ($options['is-pending'] || $options['is-maintenance-required']) {
|
||||
// If we aren't doing a maintenance check, plain pending check.
|
||||
if (!$options['is-maintenance-required']) {
|
||||
cli_error(get_string('cliupgradepending', 'core_admin'), 2);
|
||||
}
|
||||
|
||||
// Can we do this safely with no maintenance/outage? Detect if there is a schema or other application state change.
|
||||
if ($allhash !== $CFG->allcomponenthash) {
|
||||
// State change here, we need to do this in maintenance.
|
||||
cli_writeln(get_string('cliupgradepending', 'core_admin'));
|
||||
cli_error(get_string('cliupgrademaintenancerequired', 'core_admin'), 2);
|
||||
}
|
||||
|
||||
// If requested, we should always set the upgrade lock here, so this cannot be run from frontend.
|
||||
if ($options['set-ui-upgrade-lock']) {
|
||||
set_config('outagelessupgrade', true);
|
||||
cli_writeln(get_string('cliupgradesetlock', 'admin'));
|
||||
}
|
||||
|
||||
// We can do an upgrade without maintenance!
|
||||
cli_writeln(get_string('cliupgradepending', 'core_admin'));
|
||||
cli_error(get_string('cliupgrademaintenancenotrequired', 'core_admin'), 3);
|
||||
}
|
||||
|
||||
// Test environment first.
|
||||
@ -187,12 +253,18 @@ if ($interactive) {
|
||||
}
|
||||
|
||||
if ($version > $CFG->version) {
|
||||
// We purge all of MUC's caches here.
|
||||
// Caches are disabled for upgrade by CACHE_DISABLE_ALL so we must set the first arg to true.
|
||||
// This ensures a real config object is loaded and the stores will be purged.
|
||||
// This is the only way we can purge custom caches such as memcache or APC.
|
||||
// Note: all other calls to caches will still used the disabled API.
|
||||
cache_helper::purge_all(true);
|
||||
|
||||
// Only purge caches if this is a plain upgrade.
|
||||
// In the case of a no-outage upgrade, we will gracefully roll caches after upgrade.
|
||||
if ($options['maintenance']) {
|
||||
// We purge all of MUC's caches here.
|
||||
// Caches are disabled for upgrade by CACHE_DISABLE_ALL so we must set the first arg to true.
|
||||
// This ensures a real config object is loaded and the stores will be purged.
|
||||
// This is the only way we can purge custom caches such as memcache or APC.
|
||||
// Note: all other calls to caches will still used the disabled API.
|
||||
cache_helper::purge_all(true);
|
||||
}
|
||||
|
||||
upgrade_core($version, true);
|
||||
}
|
||||
set_config('release', $release);
|
||||
@ -230,4 +302,18 @@ foreach ($settingsoutput as $setting => $value) {
|
||||
upgrade_themes();
|
||||
|
||||
echo get_string('cliupgradefinished', 'admin', $a)."\n";
|
||||
|
||||
if (!$options['maintenance']) {
|
||||
cli_writeln(get_string('cliupgradecompletenomaintenanceupgrade', 'admin'));
|
||||
|
||||
// Here we check if upgrade lock has not been specifically set during this upgrade run.
|
||||
// This supports wider server orchestration actions happening, which should call with no-maintenance AND set-ui-upgrade-lock,
|
||||
// such as a new docker container deployment, of which the moodle upgrade is only a component.
|
||||
if (!$options['set-ui-upgrade-lock']) {
|
||||
// In this case we should release the lock now, as the upgrade is finished.
|
||||
// We weren't told to keep the lock with set-ui-upgrade-lock, so release.
|
||||
set_config('outagelessupgrade', false);
|
||||
}
|
||||
}
|
||||
|
||||
exit(0); // 0 means success
|
||||
|
655
admin/index.php
655
admin/index.php
@ -302,262 +302,77 @@ if (empty($CFG->version)) {
|
||||
throw new \moodle_exception('missingconfigversion', 'debug');
|
||||
}
|
||||
|
||||
// Detect config cache inconsistency, this happens when you switch branches on dev servers.
|
||||
if ($CFG->version != $DB->get_field('config', 'value', array('name'=>'version'))) {
|
||||
purge_all_caches();
|
||||
redirect(new moodle_url($PAGE->url), 'Config cache inconsistency detected, resetting caches...');
|
||||
}
|
||||
|
||||
if (!$cache and $version > $CFG->version) { // upgrade
|
||||
|
||||
$PAGE->set_url(new moodle_url($PAGE->url, array(
|
||||
'confirmupgrade' => $confirmupgrade,
|
||||
'confirmrelease' => $confirmrelease,
|
||||
'confirmplugincheck' => $confirmplugins,
|
||||
)));
|
||||
|
||||
check_upgrade_key($upgradekeyhash);
|
||||
|
||||
// Warning about upgrading a test site.
|
||||
$testsite = false;
|
||||
if (defined('BEHAT_SITE_RUNNING')) {
|
||||
$testsite = 'behat';
|
||||
// If an upgrade is running, an admin page starting a frontend upgrade could corrupt the
|
||||
// DB if the upgrade collided with an already running upgrade process at the wrong time.
|
||||
// Pull the value direct from the DB, this needs to *always* be correct.
|
||||
$outagelessupgrade = !empty($DB->get_field('config', 'value', ['name' => 'outagelessupgrade']));
|
||||
if (!$outagelessupgrade) {
|
||||
// Detect config cache inconsistency, this happens when you switch branches on dev servers.
|
||||
if ($CFG->version != $DB->get_field('config', 'value', array('name' => 'version'))) {
|
||||
purge_all_caches();
|
||||
redirect(new moodle_url($PAGE->url), 'Config cache inconsistency detected, resetting caches...');
|
||||
}
|
||||
|
||||
if (isset($CFG->themerev)) {
|
||||
// Store the themerev to restore after purging caches.
|
||||
$themerev = $CFG->themerev;
|
||||
}
|
||||
if (!$cache && $version > $CFG->version && !$outagelessupgrade) { // Upgrade.
|
||||
|
||||
// We purge all of MUC's caches here.
|
||||
// Caches are disabled for upgrade by CACHE_DISABLE_ALL so we must set the first arg to true.
|
||||
// This ensures a real config object is loaded and the stores will be purged.
|
||||
// This is the only way we can purge custom caches such as memcache or APC.
|
||||
// Note: all other calls to caches will still used the disabled API.
|
||||
cache_helper::purge_all(true);
|
||||
// We then purge the regular caches.
|
||||
purge_all_caches();
|
||||
$PAGE->set_url(new moodle_url($PAGE->url, array(
|
||||
'confirmupgrade' => $confirmupgrade,
|
||||
'confirmrelease' => $confirmrelease,
|
||||
'confirmplugincheck' => $confirmplugins,
|
||||
)));
|
||||
|
||||
if (isset($themerev)) {
|
||||
// Restore the themerev
|
||||
set_config('themerev', $themerev);
|
||||
}
|
||||
check_upgrade_key($upgradekeyhash);
|
||||
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
|
||||
if (upgrade_stale_php_files_present()) {
|
||||
$PAGE->set_title($stradministration);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
echo $output->upgrade_stale_php_files_page();
|
||||
die();
|
||||
}
|
||||
|
||||
if (empty($confirmupgrade)) {
|
||||
$a = new stdClass();
|
||||
$a->oldversion = "$CFG->release (".sprintf('%.2f', $CFG->version).")";
|
||||
$a->newversion = "$release (".sprintf('%.2f', $version).")";
|
||||
$strdatabasechecking = get_string('databasechecking', '', $a);
|
||||
|
||||
$PAGE->set_title($stradministration);
|
||||
$PAGE->set_heading($strdatabasechecking);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
echo $output->upgrade_confirm_page($a->newversion, $maturity, $testsite);
|
||||
die();
|
||||
|
||||
} else if (empty($confirmrelease)) {
|
||||
require_once($CFG->libdir.'/environmentlib.php');
|
||||
list($envstatus, $environmentresults) = check_moodle_environment($release, ENV_SELECT_RELEASE);
|
||||
$strcurrentrelease = get_string('currentrelease');
|
||||
|
||||
$PAGE->navbar->add($strcurrentrelease);
|
||||
$PAGE->set_title($strcurrentrelease);
|
||||
$PAGE->set_heading($strcurrentrelease);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
echo $output->upgrade_environment_page($release, $envstatus, $environmentresults);
|
||||
die();
|
||||
|
||||
} else if (empty($confirmplugins)) {
|
||||
$strplugincheck = get_string('plugincheck');
|
||||
|
||||
$PAGE->navbar->add($strplugincheck);
|
||||
$PAGE->set_title($strplugincheck);
|
||||
$PAGE->set_heading($strplugincheck);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
$pluginman = core_plugin_manager::instance();
|
||||
|
||||
// Check for available updates.
|
||||
if ($fetchupdates) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
$updateschecker = \core\update\checker::instance();
|
||||
if ($updateschecker->enabled()) {
|
||||
$updateschecker->fetch();
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
// Warning about upgrading a test site.
|
||||
$testsite = false;
|
||||
if (defined('BEHAT_SITE_RUNNING')) {
|
||||
$testsite = 'behat';
|
||||
}
|
||||
|
||||
// Cancel all plugin installations.
|
||||
if ($abortinstallx) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
$abortables = $pluginman->list_cancellable_installations();
|
||||
if ($abortables) {
|
||||
if ($confirmabortinstall) {
|
||||
foreach ($abortables as $plugin) {
|
||||
$pluginman->cancel_plugin_installation($plugin->component);
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
} else {
|
||||
$continue = new moodle_url($PAGE->url, array('abortinstallx' => $abortinstallx, 'confirmabortinstall' => 1));
|
||||
echo $output->upgrade_confirm_abort_install_page($abortables, $continue);
|
||||
die();
|
||||
}
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
if (isset($CFG->themerev)) {
|
||||
// Store the themerev to restore after purging caches.
|
||||
$themerev = $CFG->themerev;
|
||||
}
|
||||
|
||||
// Cancel single plugin installation.
|
||||
if ($abortinstall) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
if ($confirmabortinstall) {
|
||||
$pluginman->cancel_plugin_installation($abortinstall);
|
||||
redirect($PAGE->url);
|
||||
} else {
|
||||
$continue = new moodle_url($PAGE->url, array('abortinstall' => $abortinstall, 'confirmabortinstall' => 1));
|
||||
$abortable = $pluginman->get_plugin_info($abortinstall);
|
||||
if ($pluginman->can_cancel_plugin_installation($abortable)) {
|
||||
echo $output->upgrade_confirm_abort_install_page(array($abortable), $continue);
|
||||
die();
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
// We purge all of MUC's caches here.
|
||||
// Caches are disabled for upgrade by CACHE_DISABLE_ALL so we must set the first arg to true.
|
||||
// This ensures a real config object is loaded and the stores will be purged.
|
||||
// This is the only way we can purge custom caches such as memcache or APC.
|
||||
// Note: all other calls to caches will still used the disabled API.
|
||||
cache_helper::purge_all(true);
|
||||
// We then purge the regular caches.
|
||||
purge_all_caches();
|
||||
|
||||
if (isset($themerev)) {
|
||||
// Restore the themerev.
|
||||
set_config('themerev', $themerev);
|
||||
}
|
||||
|
||||
// Cancel all plugins upgrades (that is, restore archived versions).
|
||||
if ($abortupgradex) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
$restorable = $pluginman->list_restorable_archives();
|
||||
if ($restorable) {
|
||||
upgrade_install_plugins($restorable, $confirmabortupgrade,
|
||||
get_string('cancelupgradehead', 'core_plugin'),
|
||||
new moodle_url($PAGE->url, array('abortupgradex' => 1, 'confirmabortupgrade' => 1))
|
||||
);
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
|
||||
// Cancel single plugin upgrade (that is, install the archived version).
|
||||
if ($abortupgrade) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
$restorable = $pluginman->list_restorable_archives();
|
||||
if (isset($restorable[$abortupgrade])) {
|
||||
$restorable = array($restorable[$abortupgrade]);
|
||||
upgrade_install_plugins($restorable, $confirmabortupgrade,
|
||||
get_string('cancelupgradehead', 'core_plugin'),
|
||||
new moodle_url($PAGE->url, array('abortupgrade' => $abortupgrade, 'confirmabortupgrade' => 1))
|
||||
);
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
|
||||
// Install all available missing dependencies.
|
||||
if ($installdepx) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
$installable = $pluginman->filter_installable($pluginman->missing_dependencies(true));
|
||||
upgrade_install_plugins($installable, $confirminstalldep,
|
||||
get_string('dependencyinstallhead', 'core_plugin'),
|
||||
new moodle_url($PAGE->url, array('installdepx' => 1, 'confirminstalldep' => 1))
|
||||
);
|
||||
}
|
||||
|
||||
// Install single available missing dependency.
|
||||
if ($installdep) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
$installable = $pluginman->filter_installable($pluginman->missing_dependencies(true));
|
||||
if (!empty($installable[$installdep])) {
|
||||
$installable = array($installable[$installdep]);
|
||||
upgrade_install_plugins($installable, $confirminstalldep,
|
||||
get_string('dependencyinstallhead', 'core_plugin'),
|
||||
new moodle_url($PAGE->url, array('installdep' => $installdep, 'confirminstalldep' => 1))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Install all available updates.
|
||||
if ($installupdatex) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
$installable = $pluginman->filter_installable($pluginman->available_updates());
|
||||
upgrade_install_plugins($installable, $confirminstallupdate,
|
||||
get_string('updateavailableinstallallhead', 'core_admin'),
|
||||
new moodle_url($PAGE->url, array('installupdatex' => 1, 'confirminstallupdate' => 1))
|
||||
);
|
||||
}
|
||||
|
||||
// Install single available update.
|
||||
if ($installupdate and $installupdateversion) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
if ($pluginman->is_remote_plugin_installable($installupdate, $installupdateversion)) {
|
||||
$installable = array($pluginman->get_remote_plugin_info($installupdate, $installupdateversion, true));
|
||||
upgrade_install_plugins($installable, $confirminstallupdate,
|
||||
get_string('updateavailableinstallallhead', 'core_admin'),
|
||||
new moodle_url($PAGE->url, array('installupdate' => $installupdate,
|
||||
'installupdateversion' => $installupdateversion, 'confirminstallupdate' => 1)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
echo $output->upgrade_plugin_check_page(core_plugin_manager::instance(), \core\update\checker::instance(),
|
||||
$version, $showallplugins, $PAGE->url, new moodle_url($PAGE->url, array('confirmplugincheck' => 1)));
|
||||
die();
|
||||
|
||||
} else {
|
||||
// Always verify plugin dependencies!
|
||||
$failed = array();
|
||||
if (!core_plugin_manager::instance()->all_plugins_ok($version, $failed, $CFG->branch)) {
|
||||
echo $output->unsatisfied_dependencies_page($version, $failed, new moodle_url($PAGE->url,
|
||||
array('confirmplugincheck' => 0)));
|
||||
die();
|
||||
}
|
||||
unset($failed);
|
||||
|
||||
// Launch main upgrade.
|
||||
upgrade_core($version, true);
|
||||
}
|
||||
} else if ($version < $CFG->version) {
|
||||
// better stop here, we can not continue with plugin upgrades or anything else
|
||||
throw new moodle_exception('downgradedcore', 'error', new moodle_url('/admin/'));
|
||||
}
|
||||
|
||||
// Updated human-readable release version if necessary
|
||||
if (!$cache and $release <> $CFG->release) { // Update the release version
|
||||
set_config('release', $release);
|
||||
}
|
||||
|
||||
if (!$cache and $branch <> $CFG->branch) { // Update the branch
|
||||
set_config('branch', $branch);
|
||||
}
|
||||
|
||||
if (!$cache and moodle_needs_upgrading()) {
|
||||
|
||||
$PAGE->set_url(new moodle_url($PAGE->url, array(
|
||||
'confirmrelease' => $confirmrelease,
|
||||
'confirmplugincheck' => $confirmplugins,
|
||||
)));
|
||||
|
||||
check_upgrade_key($upgradekeyhash);
|
||||
|
||||
if (!$PAGE->headerprinted) {
|
||||
// means core upgrade or installation was not already done
|
||||
|
||||
$pluginman = core_plugin_manager::instance();
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
|
||||
if (empty($confirmrelease)) {
|
||||
require_once($CFG->libdir . '/environmentlib.php');
|
||||
if (upgrade_stale_php_files_present()) {
|
||||
$PAGE->set_title($stradministration);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
echo $output->upgrade_stale_php_files_page();
|
||||
die();
|
||||
}
|
||||
|
||||
if (empty($confirmupgrade)) {
|
||||
$a = new stdClass();
|
||||
$a->oldversion = "$CFG->release (".sprintf('%.2f', $CFG->version).")";
|
||||
$a->newversion = "$release (".sprintf('%.2f', $version).")";
|
||||
$strdatabasechecking = get_string('databasechecking', '', $a);
|
||||
|
||||
$PAGE->set_title($stradministration);
|
||||
$PAGE->set_heading($strdatabasechecking);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
echo $output->upgrade_confirm_page($a->newversion, $maturity, $testsite);
|
||||
die();
|
||||
|
||||
} else if (empty($confirmrelease)) {
|
||||
require_once($CFG->libdir.'/environmentlib.php');
|
||||
list($envstatus, $environmentresults) = check_moodle_environment($release, ENV_SELECT_RELEASE);
|
||||
$strcurrentrelease = get_string('currentrelease');
|
||||
|
||||
@ -569,7 +384,7 @@ if (!$cache and moodle_needs_upgrading()) {
|
||||
echo $output->upgrade_environment_page($release, $envstatus, $environmentresults);
|
||||
die();
|
||||
|
||||
} else if (!$confirmplugins) {
|
||||
} else if (empty($confirmplugins)) {
|
||||
$strplugincheck = get_string('plugincheck');
|
||||
|
||||
$PAGE->navbar->add($strplugincheck);
|
||||
@ -577,9 +392,11 @@ if (!$cache and moodle_needs_upgrading()) {
|
||||
$PAGE->set_heading($strplugincheck);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
$pluginman = core_plugin_manager::instance();
|
||||
|
||||
// Check for available updates.
|
||||
if ($fetchupdates) {
|
||||
require_sesskey();
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
$updateschecker = \core\update\checker::instance();
|
||||
if ($updateschecker->enabled()) {
|
||||
$updateschecker->fetch();
|
||||
@ -589,7 +406,7 @@ if (!$cache and moodle_needs_upgrading()) {
|
||||
|
||||
// Cancel all plugin installations.
|
||||
if ($abortinstallx) {
|
||||
require_sesskey();
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
$abortables = $pluginman->list_cancellable_installations();
|
||||
if ($abortables) {
|
||||
if ($confirmabortinstall) {
|
||||
@ -598,8 +415,7 @@ if (!$cache and moodle_needs_upgrading()) {
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
} else {
|
||||
$continue = new moodle_url($PAGE->url, array('abortinstallx' => $abortinstallx,
|
||||
'confirmabortinstall' => 1));
|
||||
$continue = new moodle_url($PAGE->url, ['abortinstallx' => $abortinstallx, 'confirmabortinstall' => 1]);
|
||||
echo $output->upgrade_confirm_abort_install_page($abortables, $continue);
|
||||
die();
|
||||
}
|
||||
@ -609,7 +425,7 @@ if (!$cache and moodle_needs_upgrading()) {
|
||||
|
||||
// Cancel single plugin installation.
|
||||
if ($abortinstall) {
|
||||
require_sesskey();
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
if ($confirmabortinstall) {
|
||||
$pluginman->cancel_plugin_installation($abortinstall);
|
||||
redirect($PAGE->url);
|
||||
@ -626,7 +442,7 @@ if (!$cache and moodle_needs_upgrading()) {
|
||||
|
||||
// Cancel all plugins upgrades (that is, restore archived versions).
|
||||
if ($abortupgradex) {
|
||||
require_sesskey();
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
$restorable = $pluginman->list_restorable_archives();
|
||||
if ($restorable) {
|
||||
upgrade_install_plugins($restorable, $confirmabortupgrade,
|
||||
@ -639,7 +455,7 @@ if (!$cache and moodle_needs_upgrading()) {
|
||||
|
||||
// Cancel single plugin upgrade (that is, install the archived version).
|
||||
if ($abortupgrade) {
|
||||
require_sesskey();
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
$restorable = $pluginman->list_restorable_archives();
|
||||
if (isset($restorable[$abortupgrade])) {
|
||||
$restorable = array($restorable[$abortupgrade]);
|
||||
@ -653,7 +469,7 @@ if (!$cache and moodle_needs_upgrading()) {
|
||||
|
||||
// Install all available missing dependencies.
|
||||
if ($installdepx) {
|
||||
require_sesskey();
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
$installable = $pluginman->filter_installable($pluginman->missing_dependencies(true));
|
||||
upgrade_install_plugins($installable, $confirminstalldep,
|
||||
get_string('dependencyinstallhead', 'core_plugin'),
|
||||
@ -663,7 +479,7 @@ if (!$cache and moodle_needs_upgrading()) {
|
||||
|
||||
// Install single available missing dependency.
|
||||
if ($installdep) {
|
||||
require_sesskey();
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
$installable = $pluginman->filter_installable($pluginman->missing_dependencies(true));
|
||||
if (!empty($installable[$installdep])) {
|
||||
$installable = array($installable[$installdep]);
|
||||
@ -676,7 +492,7 @@ if (!$cache and moodle_needs_upgrading()) {
|
||||
|
||||
// Install all available updates.
|
||||
if ($installupdatex) {
|
||||
require_sesskey();
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
$installable = $pluginman->filter_installable($pluginman->available_updates());
|
||||
upgrade_install_plugins($installable, $confirminstallupdate,
|
||||
get_string('updateavailableinstallallhead', 'core_admin'),
|
||||
@ -686,7 +502,7 @@ if (!$cache and moodle_needs_upgrading()) {
|
||||
|
||||
// Install single available update.
|
||||
if ($installupdate and $installupdateversion) {
|
||||
require_sesskey();
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
if ($pluginman->is_remote_plugin_installable($installupdate, $installupdateversion)) {
|
||||
$installable = array($pluginman->get_remote_plugin_info($installupdate, $installupdateversion, true));
|
||||
upgrade_install_plugins($installable, $confirminstallupdate,
|
||||
@ -698,89 +514,280 @@ if (!$cache and moodle_needs_upgrading()) {
|
||||
}
|
||||
}
|
||||
|
||||
// Show plugins info.
|
||||
echo $output->upgrade_plugin_check_page($pluginman, \core\update\checker::instance(),
|
||||
$version, $showallplugins,
|
||||
new moodle_url($PAGE->url),
|
||||
new moodle_url($PAGE->url, array('confirmplugincheck' => 1, 'cache' => 0)));
|
||||
echo $output->upgrade_plugin_check_page(core_plugin_manager::instance(), \core\update\checker::instance(),
|
||||
$version, $showallplugins, $PAGE->url, new moodle_url($PAGE->url, array('confirmplugincheck' => 1)));
|
||||
die();
|
||||
}
|
||||
|
||||
// Make sure plugin dependencies are always checked.
|
||||
$failed = array();
|
||||
if (!$pluginman->all_plugins_ok($version, $failed, $CFG->branch)) {
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
echo $output->unsatisfied_dependencies_page($version, $failed, new moodle_url($PAGE->url,
|
||||
array('confirmplugincheck' => 0)));
|
||||
die();
|
||||
}
|
||||
unset($failed);
|
||||
}
|
||||
|
||||
// install/upgrade all plugins and other parts
|
||||
upgrade_noncore(true);
|
||||
}
|
||||
|
||||
// If this is the first install, indicate that this site is fully configured
|
||||
// except the admin password
|
||||
if (during_initial_install()) {
|
||||
set_config('rolesactive', 1); // after this, during_initial_install will return false.
|
||||
set_config('adminsetuppending', 1);
|
||||
set_config('registrationpending', 1); // Remind to register site after all other setup is finished.
|
||||
|
||||
// Apply default preset, if it is defined in $CFG and has a valid value.
|
||||
if (!empty($CFG->setsitepresetduringinstall)) {
|
||||
\core_adminpresets\helper::change_default_preset($CFG->setsitepresetduringinstall);
|
||||
}
|
||||
|
||||
// we need this redirect to setup proper session
|
||||
upgrade_finished("index.php?sessionstarted=1&lang=$CFG->lang");
|
||||
}
|
||||
|
||||
// make sure admin user is created - this is the last step because we need
|
||||
// session to be working properly in order to edit admin account
|
||||
if (!empty($CFG->adminsetuppending)) {
|
||||
$sessionstarted = optional_param('sessionstarted', 0, PARAM_BOOL);
|
||||
if (!$sessionstarted) {
|
||||
redirect("index.php?sessionstarted=1&lang=$CFG->lang");
|
||||
} else {
|
||||
$sessionverify = optional_param('sessionverify', 0, PARAM_BOOL);
|
||||
if (!$sessionverify) {
|
||||
$SESSION->sessionverify = 1;
|
||||
redirect("index.php?sessionstarted=1&sessionverify=1&lang=$CFG->lang");
|
||||
} else {
|
||||
if (empty($SESSION->sessionverify)) {
|
||||
throw new \moodle_exception('installsessionerror', 'admin', "index.php?sessionstarted=1&lang=$CFG->lang");
|
||||
// Always verify plugin dependencies!
|
||||
$failed = array();
|
||||
if (!core_plugin_manager::instance()->all_plugins_ok($version, $failed, $CFG->branch)) {
|
||||
echo $output->unsatisfied_dependencies_page($version, $failed, new moodle_url($PAGE->url,
|
||||
array('confirmplugincheck' => 0)));
|
||||
die();
|
||||
}
|
||||
unset($SESSION->sessionverify);
|
||||
unset($failed);
|
||||
|
||||
// Launch main upgrade.
|
||||
upgrade_core($version, true);
|
||||
}
|
||||
} else if ($version < $CFG->version) {
|
||||
// Better stop here, we can not continue with plugin upgrades or anything else.
|
||||
throw new moodle_exception('downgradedcore', 'error', new moodle_url('/admin/'));
|
||||
}
|
||||
|
||||
// Cleanup SESSION to make sure other code does not complain in the future.
|
||||
unset($SESSION->has_timed_out);
|
||||
unset($SESSION->wantsurl);
|
||||
// Updated human-readable release version if necessary.
|
||||
if (!$cache && $release <> $CFG->release ) { // Update the release version.
|
||||
set_config('release', $release);
|
||||
}
|
||||
|
||||
// at this stage there can be only one admin unless more were added by install - users may change username, so do not rely on that
|
||||
$adminids = explode(',', $CFG->siteadmins);
|
||||
$adminuser = get_complete_user_data('id', reset($adminids));
|
||||
if (!$cache && $branch <> $CFG->branch) { // Update the branch.
|
||||
set_config('branch', $branch);
|
||||
}
|
||||
|
||||
if ($adminuser->password === 'adminsetuppending') {
|
||||
// prevent installation hijacking
|
||||
if ($adminuser->lastip !== getremoteaddr()) {
|
||||
throw new \moodle_exception('installhijacked', 'admin');
|
||||
if (!$cache && moodle_needs_upgrading()) {
|
||||
|
||||
$PAGE->set_url(new moodle_url($PAGE->url, array(
|
||||
'confirmrelease' => $confirmrelease,
|
||||
'confirmplugincheck' => $confirmplugins,
|
||||
)));
|
||||
|
||||
check_upgrade_key($upgradekeyhash);
|
||||
|
||||
if (!$PAGE->headerprinted) {
|
||||
// Means core upgrade or installation was not already done.
|
||||
|
||||
$pluginman = core_plugin_manager::instance();
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
|
||||
if (empty($confirmrelease)) {
|
||||
require_once($CFG->libdir . '/environmentlib.php');
|
||||
|
||||
list($envstatus, $environmentresults) = check_moodle_environment($release, ENV_SELECT_RELEASE);
|
||||
$strcurrentrelease = get_string('currentrelease');
|
||||
|
||||
$PAGE->navbar->add($strcurrentrelease);
|
||||
$PAGE->set_title($strcurrentrelease);
|
||||
$PAGE->set_heading($strcurrentrelease);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
echo $output->upgrade_environment_page($release, $envstatus, $environmentresults);
|
||||
die();
|
||||
|
||||
} else if (!$confirmplugins) {
|
||||
$strplugincheck = get_string('plugincheck');
|
||||
|
||||
$PAGE->navbar->add($strplugincheck);
|
||||
$PAGE->set_title($strplugincheck);
|
||||
$PAGE->set_heading($strplugincheck);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
// Check for available updates.
|
||||
if ($fetchupdates) {
|
||||
require_sesskey();
|
||||
$updateschecker = \core\update\checker::instance();
|
||||
if ($updateschecker->enabled()) {
|
||||
$updateschecker->fetch();
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
|
||||
// Cancel all plugin installations.
|
||||
if ($abortinstallx) {
|
||||
require_sesskey();
|
||||
$abortables = $pluginman->list_cancellable_installations();
|
||||
if ($abortables) {
|
||||
if ($confirmabortinstall) {
|
||||
foreach ($abortables as $plugin) {
|
||||
$pluginman->cancel_plugin_installation($plugin->component);
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
} else {
|
||||
$continue = new moodle_url($PAGE->url, array('abortinstallx' => $abortinstallx,
|
||||
'confirmabortinstall' => 1));
|
||||
echo $output->upgrade_confirm_abort_install_page($abortables, $continue);
|
||||
die();
|
||||
}
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
|
||||
// Cancel single plugin installation.
|
||||
if ($abortinstall) {
|
||||
require_sesskey();
|
||||
if ($confirmabortinstall) {
|
||||
$pluginman->cancel_plugin_installation($abortinstall);
|
||||
redirect($PAGE->url);
|
||||
} else {
|
||||
$continue = new moodle_url($PAGE->url, array('abortinstall' => $abortinstall, 'confirmabortinstall' => 1));
|
||||
$abortable = $pluginman->get_plugin_info($abortinstall);
|
||||
if ($pluginman->can_cancel_plugin_installation($abortable)) {
|
||||
echo $output->upgrade_confirm_abort_install_page(array($abortable), $continue);
|
||||
die();
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
}
|
||||
|
||||
// Cancel all plugins upgrades (that is, restore archived versions).
|
||||
if ($abortupgradex) {
|
||||
require_sesskey();
|
||||
$restorable = $pluginman->list_restorable_archives();
|
||||
if ($restorable) {
|
||||
upgrade_install_plugins($restorable, $confirmabortupgrade,
|
||||
get_string('cancelupgradehead', 'core_plugin'),
|
||||
new moodle_url($PAGE->url, array('abortupgradex' => 1, 'confirmabortupgrade' => 1))
|
||||
);
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
|
||||
// Cancel single plugin upgrade (that is, install the archived version).
|
||||
if ($abortupgrade) {
|
||||
require_sesskey();
|
||||
$restorable = $pluginman->list_restorable_archives();
|
||||
if (isset($restorable[$abortupgrade])) {
|
||||
$restorable = array($restorable[$abortupgrade]);
|
||||
upgrade_install_plugins($restorable, $confirmabortupgrade,
|
||||
get_string('cancelupgradehead', 'core_plugin'),
|
||||
new moodle_url($PAGE->url, array('abortupgrade' => $abortupgrade, 'confirmabortupgrade' => 1))
|
||||
);
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
|
||||
// Install all available missing dependencies.
|
||||
if ($installdepx) {
|
||||
require_sesskey();
|
||||
$installable = $pluginman->filter_installable($pluginman->missing_dependencies(true));
|
||||
upgrade_install_plugins($installable, $confirminstalldep,
|
||||
get_string('dependencyinstallhead', 'core_plugin'),
|
||||
new moodle_url($PAGE->url, array('installdepx' => 1, 'confirminstalldep' => 1))
|
||||
);
|
||||
}
|
||||
|
||||
// Install single available missing dependency.
|
||||
if ($installdep) {
|
||||
require_sesskey();
|
||||
$installable = $pluginman->filter_installable($pluginman->missing_dependencies(true));
|
||||
if (!empty($installable[$installdep])) {
|
||||
$installable = array($installable[$installdep]);
|
||||
upgrade_install_plugins($installable, $confirminstalldep,
|
||||
get_string('dependencyinstallhead', 'core_plugin'),
|
||||
new moodle_url($PAGE->url, array('installdep' => $installdep, 'confirminstalldep' => 1))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Install all available updates.
|
||||
if ($installupdatex) {
|
||||
require_sesskey();
|
||||
$installable = $pluginman->filter_installable($pluginman->available_updates());
|
||||
upgrade_install_plugins($installable, $confirminstallupdate,
|
||||
get_string('updateavailableinstallallhead', 'core_admin'),
|
||||
new moodle_url($PAGE->url, array('installupdatex' => 1, 'confirminstallupdate' => 1))
|
||||
);
|
||||
}
|
||||
|
||||
// Install single available update.
|
||||
if ($installupdate && $installupdateversion) {
|
||||
require_sesskey();
|
||||
if ($pluginman->is_remote_plugin_installable($installupdate, $installupdateversion)) {
|
||||
$installable = array($pluginman->get_remote_plugin_info($installupdate, $installupdateversion, true));
|
||||
upgrade_install_plugins($installable, $confirminstallupdate,
|
||||
get_string('updateavailableinstallallhead', 'core_admin'),
|
||||
new moodle_url($PAGE->url, array('installupdate' => $installupdate,
|
||||
'installupdateversion' => $installupdateversion, 'confirminstallupdate' => 1)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Show plugins info.
|
||||
echo $output->upgrade_plugin_check_page($pluginman, \core\update\checker::instance(),
|
||||
$version, $showallplugins,
|
||||
new moodle_url($PAGE->url),
|
||||
new moodle_url($PAGE->url, array('confirmplugincheck' => 1, 'cache' => 0)));
|
||||
die();
|
||||
}
|
||||
|
||||
// Make sure plugin dependencies are always checked.
|
||||
$failed = array();
|
||||
if (!$pluginman->all_plugins_ok($version, $failed, $CFG->branch)) {
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
echo $output->unsatisfied_dependencies_page($version, $failed, new moodle_url($PAGE->url,
|
||||
array('confirmplugincheck' => 0)));
|
||||
die();
|
||||
}
|
||||
unset($failed);
|
||||
}
|
||||
|
||||
// Install/upgrade all plugins and other parts.
|
||||
upgrade_noncore(true);
|
||||
}
|
||||
|
||||
// If this is the first install, indicate that this site is fully configured,
|
||||
// Except the admin password.
|
||||
if (during_initial_install()) {
|
||||
set_config('rolesactive', 1); // After this, during_initial_install will return false.
|
||||
set_config('adminsetuppending', 1);
|
||||
set_config('registrationpending', 1); // Remind to register site after all other setup is finished.
|
||||
|
||||
// Apply default preset, if it is defined in $CFG and has a valid value.
|
||||
if (!empty($CFG->setsitepresetduringinstall)) {
|
||||
\core_adminpresets\helper::change_default_preset($CFG->setsitepresetduringinstall);
|
||||
}
|
||||
|
||||
// We need this redirect to setup proper session.
|
||||
upgrade_finished("index.php?sessionstarted=1&lang=$CFG->lang");
|
||||
}
|
||||
|
||||
// Make sure admin user is created - this is the last step,
|
||||
// We need session to be working properly in order to edit admin account.
|
||||
if (!empty($CFG->adminsetuppending)) {
|
||||
$sessionstarted = optional_param('sessionstarted', 0, PARAM_BOOL);
|
||||
if (!$sessionstarted) {
|
||||
redirect("index.php?sessionstarted=1&lang=$CFG->lang");
|
||||
} else {
|
||||
$sessionverify = optional_param('sessionverify', 0, PARAM_BOOL);
|
||||
if (!$sessionverify) {
|
||||
$SESSION->sessionverify = 1;
|
||||
redirect("index.php?sessionstarted=1&sessionverify=1&lang=$CFG->lang");
|
||||
} else {
|
||||
if (empty($SESSION->sessionverify)) {
|
||||
throw new \moodle_exception('installsessionerror', 'admin', "index.php?sessionstarted=1&lang=$CFG->lang");
|
||||
}
|
||||
unset($SESSION->sessionverify);
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup SESSION to make sure other code does not complain in the future.
|
||||
unset($SESSION->has_timed_out);
|
||||
unset($SESSION->wantsurl);
|
||||
|
||||
// At this stage there can be only one admin unless more were added by install,
|
||||
// Users may change username, so do not rely on that.
|
||||
$adminids = explode(',', $CFG->siteadmins);
|
||||
$adminuser = get_complete_user_data('id', reset($adminids));
|
||||
|
||||
if ($adminuser->password === 'adminsetuppending') {
|
||||
// Prevent installation hijacking.
|
||||
if ($adminuser->lastip !== getremoteaddr()) {
|
||||
throw new \moodle_exception('installhijacked', 'admin');
|
||||
}
|
||||
// Login user and let him set password and admin details.
|
||||
$adminuser->newadminuser = 1;
|
||||
complete_user_login($adminuser);
|
||||
redirect("$CFG->wwwroot/user/editadvanced.php?id=$adminuser->id"); // Edit thyself.
|
||||
|
||||
} else {
|
||||
unset_config('adminsetuppending');
|
||||
}
|
||||
// login user and let him set password and admin details
|
||||
$adminuser->newadminuser = 1;
|
||||
complete_user_login($adminuser);
|
||||
redirect("$CFG->wwwroot/user/editadvanced.php?id=$adminuser->id"); // Edit thyself
|
||||
|
||||
} else {
|
||||
unset_config('adminsetuppending');
|
||||
// Just make sure upgrade logging is properly terminated.
|
||||
upgrade_finished('upgradesettings.php');
|
||||
}
|
||||
|
||||
} else {
|
||||
// just make sure upgrade logging is properly terminated
|
||||
upgrade_finished('upgradesettings.php');
|
||||
}
|
||||
|
||||
if (has_capability('moodle/site:config', context_system::instance())) {
|
||||
|
@ -138,12 +138,24 @@ $string['clitypevaluedefault'] = 'type value, press Enter to use default value (
|
||||
$string['cliunknowoption'] = 'Unrecognised options:
|
||||
{$a}
|
||||
Please use --help option.';
|
||||
$string['cliupgradecompletenomaintenanceupgrade'] = 'To purge remaining caches after user traffic cutover to new code:
|
||||
|
||||
php admin/cli/purge_caches.php --muc
|
||||
php admin/cli/purge_caches.php --js
|
||||
php admin/cli/purge_caches.php --filter
|
||||
php admin/cli/purge_caches.php --other
|
||||
|
||||
It is recommended to perform these purges in isolation, with a gap between commands, to reduce load spikes on the web server.';
|
||||
$string['cliupgradedefault'] = 'New setting: {$a}';
|
||||
$string['cliupgradedefaultheading'] = 'Setting new default values';
|
||||
$string['cliupgradedefaultverbose'] = 'New setting: {$a->name}, Default value: {$a->defaultsetting}';
|
||||
$string['cliupgradefinished'] = 'Command line upgrade from {$a->oldversion} to {$a->newversion} completed successfully.';
|
||||
$string['cliupgrademaintenancenotrequired'] = 'This upgrade WILL NOT result in maintenance mode for users.';
|
||||
$string['cliupgrademaintenancerequired'] = 'This upgrade WILL result in maintenance mode for users.';
|
||||
$string['cliupgradenoneed'] = 'No upgrade needed for the installed version {$a}. Thanks for coming anyway!';
|
||||
$string['cliupgradepending'] = 'An upgrade is pending';
|
||||
$string['cliupgradesetlock'] = 'Upgrade has been locked to CLI execution only.';
|
||||
$string['cliupgradeunsetlock'] = 'Existing CLI execution upgrade lock has been removed.';
|
||||
$string['cliyesnoprompt'] = 'type y (means yes) or n (means no)';
|
||||
$string['close'] = 'Close';
|
||||
$string['commentsperpage'] = 'Comments displayed per page';
|
||||
|
@ -1195,6 +1195,80 @@ $cache = '.var_export($cache, true).';
|
||||
return $versions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns hash of all core + plugin /db/ directories.
|
||||
*
|
||||
* This is relatively slow and not fully cached, use with care!
|
||||
*
|
||||
* @param array|null $components optional component directory => hash array to use. Only used in PHPUnit.
|
||||
* @return string sha1 hash.
|
||||
*/
|
||||
public static function get_all_component_hash(?array $components = null) : string {
|
||||
$tohash = $components ?? self::get_all_directory_hashes();
|
||||
return sha1(serialize($tohash));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the hashes of all core + plugin /db/ directories.
|
||||
*
|
||||
* @param array|null $directories optional component directory array to hash. Only used in PHPUnit.
|
||||
* @return array of directory => hash.
|
||||
*/
|
||||
public static function get_all_directory_hashes(?array $directories = null) : array {
|
||||
global $CFG;
|
||||
|
||||
self::init();
|
||||
|
||||
// The problem here is that the component cache might be stale,
|
||||
// we want this to work also on frontpage without resetting the component cache.
|
||||
$usecache = false;
|
||||
if (CACHE_DISABLE_ALL || (defined('IGNORE_COMPONENT_CACHE') && IGNORE_COMPONENT_CACHE)) {
|
||||
$usecache = true;
|
||||
}
|
||||
|
||||
if (empty($directories)) {
|
||||
$directories = [
|
||||
$CFG->libdir . '/db'
|
||||
];
|
||||
// For all components, get the directory of the /db directory.
|
||||
$plugintypes = self::get_plugin_types();
|
||||
foreach ($plugintypes as $type => $typedir) {
|
||||
if ($usecache) {
|
||||
$plugs = self::get_plugin_list($type);
|
||||
} else {
|
||||
$plugs = self::fetch_plugins($type, $typedir);
|
||||
}
|
||||
foreach ($plugs as $plug) {
|
||||
$directories[] = $plug . '/db';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create a mapping of directories to their hash.
|
||||
$hashes = [];
|
||||
foreach ($directories as $directory) {
|
||||
if (!is_dir($directory)) {
|
||||
// Just hash an empty string as the non-existing representation.
|
||||
$hashes[$directory] = sha1('');
|
||||
continue;
|
||||
}
|
||||
|
||||
$scan = scandir($directory);
|
||||
$scanhashes = [];
|
||||
foreach ($scan as $file) {
|
||||
$file = $directory . '/' . $file;
|
||||
// Moodle ignores directories.
|
||||
if (!is_dir($file)) {
|
||||
$scanhashes[] = hash_file('sha1', $file);
|
||||
}
|
||||
}
|
||||
// Finally we can serialize and hash the whole dir.
|
||||
$hashes[$directory] = sha1(serialize($scanhashes));
|
||||
}
|
||||
|
||||
return $hashes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate opcode cache for given file, this is intended for
|
||||
* php files that are stored in dataroot.
|
||||
|
@ -8231,10 +8231,23 @@ function check_php_version($version='5.2.4') {
|
||||
* Checks version numbers of main code and all plugins to see
|
||||
* if there are any mismatches.
|
||||
*
|
||||
* @param bool $checkupgradeflag check the outagelessupgrade flag to see if an upgrade is running.
|
||||
* @return bool
|
||||
*/
|
||||
function moodle_needs_upgrading() {
|
||||
global $CFG;
|
||||
function moodle_needs_upgrading($checkupgradeflag = true) {
|
||||
global $CFG, $DB;
|
||||
|
||||
// Say no if there is already an upgrade running.
|
||||
if ($checkupgradeflag) {
|
||||
$lock = $DB->get_field('config', 'value', ['name' => 'outagelessupgrade']);
|
||||
$currentprocessrunningupgrade = (defined('CLI_UPGRADE_RUNNING') && CLI_UPGRADE_RUNNING);
|
||||
// If we ARE locked, but this PHP process is NOT the process running the upgrade,
|
||||
// We should always return false.
|
||||
// This means the upgrade is running from CLI somewhere, or about to.
|
||||
if (!empty($lock) && !$currentprocessrunningupgrade) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($CFG->version)) {
|
||||
return true;
|
||||
|
@ -946,4 +946,35 @@ class component_test extends advanced_testcase {
|
||||
// The function will return false for a non-existent component.
|
||||
$this->assertFalse(core_component::has_monologo_icon('randomcomponent', 'h5p'));
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests the getter for the db directory summary hash.
|
||||
*
|
||||
* @covers \core_component::get_all_directory_hashes
|
||||
*/
|
||||
public function test_get_db_directories_hash() {
|
||||
$initial = \core_component::get_all_component_hash();
|
||||
|
||||
$dir = make_request_directory();
|
||||
$hashes = \core_component::get_all_directory_hashes([$dir]);
|
||||
$emptydirhash = \core_component::get_all_component_hash([$hashes]);
|
||||
|
||||
// Confirm that a single empty directory is a different hash to the core hash.
|
||||
$this->assertNotEquals($initial, $emptydirhash);
|
||||
|
||||
// Now lets add something to the dir, and check the hash is different.
|
||||
$file = fopen($dir . '/test.php', 'w');
|
||||
fwrite($file, 'sometestdata');
|
||||
fclose($file);
|
||||
|
||||
$hashes = \core_component::get_all_directory_hashes([$dir]);
|
||||
$onefiledirhash = \core_component::get_all_component_hash([$hashes]);
|
||||
$this->assertNotEquals($emptydirhash, $onefiledirhash);
|
||||
|
||||
// Now add a subdirectory inside the request dir. This should not affect the hash.
|
||||
mkdir($dir . '/subdir');
|
||||
$hashes = \core_component::get_all_directory_hashes([$dir]);
|
||||
$finalhash = \core_component::get_all_component_hash([$hashes]);
|
||||
$this->assertEquals($onefiledirhash, $finalhash);
|
||||
}
|
||||
}
|
||||
|
@ -1504,4 +1504,108 @@ calendar,core_calendar|/calendar/view.php?view=month',
|
||||
$this->assertTrue($updatedold->timecreated >= $origtime);
|
||||
$this->assertTrue($updatedold->timemodified >= $origtime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the upgrade status check alongside the outageless flags.
|
||||
*
|
||||
* @covers ::moodle_needs_upgrading
|
||||
*/
|
||||
public function test_moodle_upgrade_check_outageless() {
|
||||
global $CFG;
|
||||
$this->resetAfterTest();
|
||||
// Get a baseline.
|
||||
$this->assertFalse(moodle_needs_upgrading());
|
||||
|
||||
// First lets check a plain upgrade ready.
|
||||
$CFG->version = '';
|
||||
$this->assertTrue(moodle_needs_upgrading());
|
||||
|
||||
// Now set the locking config and confirm we shouldn't upgrade.
|
||||
set_config('outagelessupgrade', true);
|
||||
$this->assertFalse(moodle_needs_upgrading());
|
||||
|
||||
// Test the ignorelock flag is functioning.
|
||||
$this->assertTrue(moodle_needs_upgrading(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the upgrade status check alongside the outageless flags.
|
||||
*
|
||||
* @covers ::upgrade_started
|
||||
*/
|
||||
public function test_moodle_start_upgrade_outageless() {
|
||||
global $CFG;
|
||||
$this->resetAfterTest();
|
||||
$this->assertObjectNotHasAttribute('upgraderunning', $CFG);
|
||||
|
||||
// Confirm that starting normally sets the upgraderunning flag.
|
||||
upgrade_started();
|
||||
$upgrade = get_config('core', 'upgraderunning');
|
||||
$this->assertTrue($upgrade > (time() - 5));
|
||||
|
||||
// Confirm that the config flag doesnt affect the internal upgrade processes.
|
||||
unset($CFG->upgraderunning);
|
||||
set_config('upgraderunning', null);
|
||||
set_config('outagelessupgrade', true);
|
||||
upgrade_started();
|
||||
$upgrade = get_config('core', 'upgraderunning');
|
||||
$this->assertTrue($upgrade > (time() - 5));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the upgrade timeout setter alongside the outageless flags.
|
||||
*
|
||||
* @covers ::upgrade_set_timeout
|
||||
*/
|
||||
public function test_moodle_set_upgrade_timeout_outageless() {
|
||||
global $CFG;
|
||||
$this->resetAfterTest();
|
||||
$this->assertObjectNotHasAttribute('upgraderunning', $CFG);
|
||||
|
||||
// Confirm running normally sets the timeout.
|
||||
upgrade_set_timeout(120);
|
||||
$upgrade = get_config('core', 'upgraderunning');
|
||||
$this->assertTrue($upgrade > (time() - 5));
|
||||
|
||||
// Confirm that the config flag doesnt affect the internal upgrade processes.
|
||||
unset($CFG->upgraderunning);
|
||||
set_config('upgraderunning', null);
|
||||
set_config('outagelessupgrade', true);
|
||||
upgrade_set_timeout(120);
|
||||
$upgrade = get_config('core', 'upgraderunning');
|
||||
$this->assertTrue($upgrade > (time() - 5));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the components of the upgrade process being run outageless.
|
||||
*
|
||||
* @covers ::moodle_needs_upgrading
|
||||
* @covers ::upgrade_started
|
||||
* @covers ::upgrade_set_timeout
|
||||
*/
|
||||
public function test_upgrade_components_with_outageless() {
|
||||
global $CFG;
|
||||
$this->resetAfterTest();
|
||||
|
||||
// We can now define the outageless constant for use in upgrade, and test the effects.
|
||||
define('CLI_UPGRADE_RUNNING', true);
|
||||
|
||||
// First test the upgrade check. Even when locked via config this should return true.
|
||||
// This can happen when attempting to fix a broken upgrade, so needs to work.
|
||||
set_config('outagelessupgrade', true);
|
||||
$CFG->version = '';
|
||||
$this->assertTrue(moodle_needs_upgrading());
|
||||
|
||||
// Now confirm that starting upgrade with the constant will not set the upgraderunning flag.
|
||||
set_config('upgraderunning', null);
|
||||
upgrade_started();
|
||||
$upgrade = get_config('core', 'upgraderunning');
|
||||
$this->assertFalse($upgrade);
|
||||
|
||||
// The same for timeouts, it should not be set if the constant is set.
|
||||
set_config('upgraderunning', null);
|
||||
upgrade_set_timeout(120);
|
||||
$upgrade = get_config('core', 'upgraderunning');
|
||||
$this->assertFalse($upgrade);
|
||||
}
|
||||
}
|
||||
|
@ -278,6 +278,11 @@ class core_upgrade_time {
|
||||
function upgrade_set_timeout($max_execution_time=300) {
|
||||
global $CFG;
|
||||
|
||||
// Support outageless upgrades.
|
||||
if (defined('CLI_UPGRADE_RUNNING') && CLI_UPGRADE_RUNNING) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isset($CFG->upgraderunning) or $CFG->upgraderunning < time()) {
|
||||
$upgraderunning = get_config(null, 'upgraderunning');
|
||||
} else {
|
||||
@ -1589,7 +1594,10 @@ function upgrade_started($preinstall=false) {
|
||||
ignore_user_abort(true);
|
||||
core_shutdown_manager::register_function('upgrade_finished_handler');
|
||||
upgrade_setup_debug(true);
|
||||
set_config('upgraderunning', time()+300);
|
||||
// Support no-maintenance upgrades.
|
||||
if (!defined('CLI_UPGRADE_RUNNING') || !CLI_UPGRADE_RUNNING) {
|
||||
set_config('upgraderunning', time() + 300);
|
||||
}
|
||||
$started = true;
|
||||
}
|
||||
}
|
||||
@ -1873,9 +1881,11 @@ function upgrade_core($version, $verbose) {
|
||||
require_once($CFG->libdir.'/db/upgrade.php'); // Defines upgrades
|
||||
|
||||
try {
|
||||
// Reset caches before any output.
|
||||
cache_helper::purge_all(true);
|
||||
purge_all_caches();
|
||||
// If we are in maintenance, we can purge all our caches here.
|
||||
if (!defined('CLI_UPGRADE_RUNNING') || !CLI_UPGRADE_RUNNING) {
|
||||
cache_helper::purge_all(true);
|
||||
purge_all_caches();
|
||||
}
|
||||
|
||||
// Upgrade current language pack if we can
|
||||
upgrade_language_pack();
|
||||
@ -1910,10 +1920,12 @@ function upgrade_core($version, $verbose) {
|
||||
core_upgrade_time::record_detail('cache_helper::update_definitions');
|
||||
|
||||
// Purge caches again, just to be sure we arn't holding onto old stuff now.
|
||||
cache_helper::purge_all(true);
|
||||
core_upgrade_time::record_detail('cache_helper::purge_all');
|
||||
purge_all_caches();
|
||||
core_upgrade_time::record_detail('purge_all_caches');
|
||||
if (!defined('CLI_UPGRADE_RUNNING') || !CLI_UPGRADE_RUNNING) {
|
||||
cache_helper::purge_all(true);
|
||||
core_upgrade_time::record_detail('cache_helper::purge_all');
|
||||
purge_all_caches();
|
||||
core_upgrade_time::record_detail('purge_all_caches');
|
||||
}
|
||||
|
||||
// Clean up contexts - more and more stuff depends on existence of paths and contexts
|
||||
context_helper::cleanup_instances();
|
||||
@ -1950,9 +1962,11 @@ function upgrade_noncore($verbose) {
|
||||
|
||||
// upgrade all plugins types
|
||||
try {
|
||||
// Reset caches before any output.
|
||||
cache_helper::purge_all(true);
|
||||
purge_all_caches();
|
||||
// Reset caches before any output, unless we are not in maintenance.
|
||||
if (!defined('CLI_UPGRADE_RUNNING') || !CLI_UPGRADE_RUNNING) {
|
||||
cache_helper::purge_all(true);
|
||||
purge_all_caches();
|
||||
}
|
||||
|
||||
$plugintypes = core_component::get_plugin_types();
|
||||
upgrade_started();
|
||||
@ -1976,12 +1990,16 @@ function upgrade_noncore($verbose) {
|
||||
// Mark the site as upgraded.
|
||||
set_config('allversionshash', core_component::get_all_versions_hash());
|
||||
core_upgrade_time::record_detail('core_component::get_all_versions_hash');
|
||||
set_config('allcomponenthash', core_component::get_all_component_hash());
|
||||
core_upgrade_time::record_detail('core_component::get_all_component_hash');
|
||||
|
||||
// Purge caches again, just to be sure we arn't holding onto old stuff now.
|
||||
cache_helper::purge_all(true);
|
||||
core_upgrade_time::record_detail('cache_helper::purge_all');
|
||||
purge_all_caches();
|
||||
core_upgrade_time::record_detail('purge_all_caches');
|
||||
if (!defined('CLI_UPGRADE_RUNNING') || !CLI_UPGRADE_RUNNING) {
|
||||
cache_helper::purge_all(true);
|
||||
core_upgrade_time::record_detail('cache_helper::purge_all');
|
||||
purge_all_caches();
|
||||
core_upgrade_time::record_detail('purge_all_caches');
|
||||
}
|
||||
|
||||
// Only display the final 'Success' if we also showed the heading.
|
||||
core_upgrade_time::record_end($CFG->debugdeveloper);
|
||||
|
Loading…
x
Reference in New Issue
Block a user