Remove migration assistance (#1275)

It's time to get rid of this. Anyone who didn't migrate yet won't be
convinced by this anymore either.
This commit is contained in:
Johannes Meyer 2025-11-06 09:37:05 +01:00 committed by GitHub
commit f23525a4e5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 17 additions and 443 deletions

View file

@ -4,70 +4,13 @@
namespace Icinga\Module\Icingadb\Controllers;
use Exception;
use GuzzleHttp\Psr7\ServerRequest;
use Icinga\Application\Hook;
use Icinga\Application\Icinga;
use Icinga\Exception\IcingaException;
use Icinga\Module\Icingadb\Compat\UrlMigrator;
use Icinga\Module\Icingadb\Forms\SetAsBackendForm;
use Icinga\Module\Icingadb\Hook\IcingadbSupportHook;
use Icinga\Module\Icingadb\Web\Controller;
use ipl\Html\HtmlString;
use ipl\Stdlib\Filter;
use ipl\Web\Filter\QueryString;
use ipl\Web\Url;
class MigrateController extends Controller
{
public function monitoringUrlAction()
{
$this->assertHttpMethod('post');
if (! $this->getRequest()->isApiRequest()) {
$this->httpBadRequest('No API request');
}
if (
! preg_match('/([^;]*);?/', $this->getRequest()->getHeader('Content-Type'), $matches)
|| $matches[1] !== 'application/json'
) {
$this->httpBadRequest('No JSON content');
}
$urls = $this->getRequest()->getPost();
$result = [];
$errors = [];
foreach ($urls as $urlString) {
$url = Url::fromPath($urlString);
if (UrlMigrator::isSupportedUrl($url)) {
try {
$urlString = rawurldecode(UrlMigrator::transformUrl($url)->getAbsoluteUrl());
} catch (Exception $e) {
$errors[$urlString] = [
IcingaException::describe($e),
IcingaException::getConfidentialTraceAsString($e)
];
$urlString = false;
}
}
$result[] = $urlString;
}
$response = $this->getResponse()->json();
if (empty($errors)) {
$response->setSuccessData($result);
} else {
$response->setFailData([
'result' => $result,
'errors' => $errors
]);
}
$response->sendResponse();
}
public function searchUrlAction()
{
$this->assertHttpMethod('post');
@ -107,63 +50,4 @@ class MigrateController extends Controller
$response->sendResponse();
}
public function checkboxStateAction()
{
$this->assertHttpMethod('get');
$form = new SetAsBackendForm();
$form->setAction(Url::fromPath('icingadb/migrate/checkbox-submit')->getAbsoluteUrl());
$this->getDocument()->addHtml($form);
}
public function checkboxSubmitAction()
{
$this->assertHttpMethod('post');
$this->addPart(HtmlString::create('"bogus"'), 'Behavior:Migrate');
(new SetAsBackendForm())->handleRequest(ServerRequest::fromGlobals());
}
public function backendSupportAction()
{
$this->assertHttpMethod('post');
if (! $this->getRequest()->isApiRequest()) {
$this->httpBadRequest('No API request');
}
if (
! preg_match('/([^;]*);?/', $this->getRequest()->getHeader('Content-Type'), $matches)
|| $matches[1] !== 'application/json'
) {
$this->httpBadRequest('No JSON content');
}
$moduleSupportStates = [];
if (
Icinga::app()->getModuleManager()->hasEnabled('monitoring')
&& $this->Auth()->hasPermission('module/monitoring')
) {
$supportList = [];
foreach (Hook::all('Icingadb/IcingadbSupport') as $hook) {
/** @var IcingadbSupportHook $hook */
$supportList[$hook->getModule()->getName()] = $hook->supportsIcingaDb();
}
$moduleSupportStates = [];
foreach ($this->getRequest()->getPost() as $moduleName) {
if (isset($supportList[$moduleName])) {
$moduleSupportStates[] = $supportList[$moduleName];
} else {
$moduleSupportStates[] = false;
}
}
}
$this->getResponse()
->json()
->setSuccessData($moduleSupportStates)
->sendResponse();
}
}

View file

@ -1,34 +0,0 @@
<?php
/* Icinga DB Web | (c) 2021 Icinga GmbH | GPLv2 */
namespace Icinga\Module\Icingadb\Forms;
use Icinga\Module\Icingadb\Hook\IcingadbSupportHook;
use Icinga\Web\Session;
use ipl\Web\Compat\CompatForm;
class SetAsBackendForm extends CompatForm
{
protected $defaultAttributes = [
'id' => 'setAsBackendForm',
'class' => 'icinga-controls'
];
protected function assemble()
{
$this->addElement('checkbox', 'backend', [
'class' => 'autosubmit',
'label' => t('Use Icinga DB As Backend'),
'value' => IcingadbSupportHook::isIcingaDbSetAsPreferredBackend()
]);
}
public function onSuccess()
{
Session::getSession()->getNamespace('icingadb')->set(
IcingadbSupportHook::PREFERENCE_NAME,
$this->getElement('backend')->isChecked()
);
}
}

View file

@ -3,6 +3,14 @@
Specific version upgrades are described below. Please note that version upgrades are incremental.
If you are upgrading across multiple versions, make sure to follow the steps for each of them.
## Upgrading to Icinga DB Web v1.3
**Removed Features**
* The migration widget in the top right is not toggled anymore for monitoring views, nor does it allow choosing
the preferred backend type for modules with support for IDO and Icinga DB. The default backend type is now
always Icinga DB.
## Upgrading to Icinga DB Web v1.2
**Requirements**

View file

@ -69,36 +69,6 @@ expects a username, with optional wildcards (`*`) to match multiple users. `--us
Pass `--no-backup` to disable backup creation. Please note, if you do so, that this makes resetting
changes more difficult.
### Automation
For those who integrate Icinga Web into e.g. custom dashboards, there is also a way to automate the
migration of urls. An API endpoint in Icinga DB Web allows for this:
`/icingaweb2/icingadb/migrate/monitoring-url`
If you `POST` a JSON list there, you'll get a JSON list back with the transformed urls in it.
The returned list is ordered the same and any unrecognized url is left unchanged:
**Input:**
```json
[
"/icingaweb2/monitoring/list/services?hostgroup_name=prod-hosts|(_host_env=prod&_host_stage!=testing)",
"/icingaweb2/businessprocess/process/show?config=production"
]
```
**Output**:
```json
[
"/icingaweb2/icingadb/services?hostgroup.name=prod-hosts|(host.vars.env=prod&host.vars.stage!=testing)",
"/icingaweb2/businessprocess/process/show?config=production"
]
```
**curl example:**
`curl -s -HContent-Type:application/json -HAccept:application/json -u icingaadmin:icinga http://localhost/icingaweb2/icingadb/migrate/monitoring-url -d '["/icingaweb2/monitoring/list/services?hostgroup_name=prod-hosts|(_host_env=prod&_host_stage!=testing)","/icingaweb2/businessprocess/process/show?config=production"]'`
## Views and Exports
### Url Parameter `addColumns`

View file

@ -13,9 +13,6 @@ abstract class IcingadbSupportHook
{
use HookUtils;
/** @var string key name of preference */
const PREFERENCE_NAME = 'icingadb.as_backend';
/**
* Return whether your module supports IcingaDB or not
*
@ -33,9 +30,7 @@ abstract class IcingadbSupportHook
*/
final public static function isIcingaDbSetAsPreferredBackend(): bool
{
return (bool) Session::getSession()
->getNamespace('icingadb')
->get(self::PREFERENCE_NAME, false);
return true;
}
/**

View file

@ -98,9 +98,7 @@
color: @text-color-light;
}
form ~ .monitoring-migration-hint,
.search-migration-suggestions:not(:empty) + .search-migration-hint,
.monitoring-migration-suggestions:not(:empty) + .monitoring-migration-hint {
.search-migration-suggestions:not(:empty) + .search-migration-hint {
display: block;
}
@ -155,27 +153,5 @@
}
}
}
form {
width: 100%;
.control-group {
display: flex;
align-items: center;
.control-label-group {
margin-right: .5em;
}
label {
margin-left: auto;
}
}
}
.search-migration-suggestions:not(:empty) ~ form,
.search-migration-suggestions:not(:empty) ~ .monitoring-migration-suggestions:not(:empty) {
margin-bottom: .5em;
}
}
}

View file

@ -12,8 +12,6 @@
' <button type="button" class="close">Don\'t show this again</button>\n' +
' <ul class="search-migration-suggestions"></ul>\n' +
' <p class="search-migration-hint">Miss some results? Try the link(s) below</p>\n' +
' <ul class="monitoring-migration-suggestions"></ul>\n' +
' <p class="monitoring-migration-hint">Preview this in Icinga DB</p>\n' +
' </div>\n' +
' <div class="minimizer"><i class="icon-"></i></div>\n' +
' </div>\n' +
@ -36,11 +34,7 @@
super(icinga);
this.knownMigrations = {};
this.knownBackendSupport = {};
this.urlMigrationReadyState = null;
this.backendSupportReadyState = null;
this.searchMigrationReadyState = null;
this.backendSupportRelated = {};
this.$popup = null;
// Some persistence, we don't want to annoy our users too much
@ -49,9 +43,6 @@
this.tempStorage.setBackend(window.sessionStorage);
this.previousMigrations = {};
// We don't want to ask the server to migrate non-monitoring urls
this.isMonitoringUrl = new RegExp('^' + icinga.config.baseUrl + '/monitoring/');
this.on('rendered', this.onRendered, this);
this.on('close-column', this.onColumnClose, this);
this.on('click', '#migrate-popup button.close', this.onClose, this);
@ -60,19 +51,6 @@
this.storage.onChange('minimized', this.onMinimized, this);
}
update(data) {
if (data !== 'bogus') {
return;
}
$.each(this.backendSupportRelated, (id, _) => {
let $container = $('#' + id);
let req = this.icinga.loader.loadUrl($container.data('icingaUrl'), $container);
req.addToHistory = false;
req.scripted = true;
});
}
onRendered(event) {
var _this = event.data.self;
var $target = $(event.target);
@ -109,9 +87,7 @@
}
prepareMigration($target) {
let monitoringUrls = {};
let searchUrls = {};
let modules = {}
$target.each((_, container) => {
let $container = $(container);
@ -125,27 +101,13 @@
) {
delete this.previousMigrations[containerId];
} else {
if (href.match(this.isMonitoringUrl)) {
monitoringUrls[containerId] = href;
} else if ($container.find('[data-enrichment-type="search-bar"]').length) {
if ($container.find('[data-enrichment-type="search-bar"]').length) {
searchUrls[containerId] = href;
}
}
}
let moduleName = $container.data('icingaModule');
if (!! moduleName && moduleName !== 'default' && moduleName !== 'monitoring' && moduleName !== 'icingadb') {
modules[containerId] = moduleName;
}
});
if (Object.keys(monitoringUrls).length) {
this.setUrlMigrationReadyState(false);
this.migrateUrls(monitoringUrls, 'monitoring');
} else {
this.setUrlMigrationReadyState(null);
}
if (Object.keys(searchUrls).length) {
this.setSearchMigrationReadyState(false);
this.migrateUrls(searchUrls, 'search');
@ -153,18 +115,7 @@
this.setSearchMigrationReadyState(null);
}
if (Object.keys(modules).length) {
this.setBackendSupportReadyState(false);
this.prepareBackendCheckboxForm(modules);
} else {
this.setBackendSupportReadyState(null);
}
if (
this.urlMigrationReadyState === null
&& this.backendSupportReadyState === null
&& this.searchMigrationReadyState === null
) {
if (this.searchMigrationReadyState === null) {
this.cleanupPopup();
}
}
@ -193,21 +144,6 @@
}
});
let backendSupportRelated = { ..._this.backendSupportRelated };
$.each(backendSupportRelated, (id, module) => {
let $container = $('#' + id);
if (! $container.length || $container.data('icingaModule') !== module) {
let $newContainer = $('#main > .container').filter(function () {
return $(this).data('icingaModule') === module;
});
if ($newContainer.length) {
_this.backendSupportRelated[$newContainer.attr('id')] = module;
}
delete _this.backendSupportRelated[id];
}
});
_this.cleanupPopup();
}
@ -239,7 +175,7 @@
_this.knownMigrations[containerUrl] = false;
}
if (_this.Popup().find('li').length === 1 && ! _this.Popup().find('#setAsBackendForm').length) {
if (_this.Popup().find('li').length === 1) {
_this.hidePopup(function () {
// Let the transition finish first, looks cleaner
$suggestion.remove();
@ -276,14 +212,8 @@
}
});
let endpoint, changeCallback;
if (type === 'monitoring') {
endpoint = 'monitoring-url';
changeCallback = this.changeUrlMigrationReadyState.bind(this);
} else {
endpoint = 'search-url';
changeCallback = this.changeSearchMigrationReadyState.bind(this);
}
const endpoint = 'search-url';
const changeCallback = this.changeSearchMigrationReadyState.bind(this);
if (containerUrls.length) {
var req = $.ajax({
@ -329,94 +259,8 @@
this.addSuggestions(req.urls, req.suggestionType);
}
prepareBackendCheckboxForm(modules) {
let containerIds = [];
let moduleNames = [];
$.each(modules, (id, module) => {
if (typeof this.knownBackendSupport[module] === 'undefined') {
containerIds.push(id);
moduleNames.push(module);
}
});
if (moduleNames.length) {
let req = $.ajax({
context : this,
type : 'post',
url : this.icinga.config.baseUrl + '/icingadb/migrate/backend-support',
headers : { 'Accept': 'application/json' },
contentType : 'application/json',
data : JSON.stringify(moduleNames)
});
req.modules = modules;
req.moduleIndexToContainerId = containerIds;
req.done(this.processBackendSupportResults);
req.always(() => this.changeBackendSupportReadyState(true));
} else {
// All modules have already been checked once, show popup immediately
this.setupBackendCheckboxForm(modules);
this.changeBackendSupportReadyState(true);
}
}
processBackendSupportResults(data, textStatus, req) {
let result = data.data;
$.each(result, (i, state) => {
let containerId = req.moduleIndexToContainerId[i];
this.knownBackendSupport[req.modules[containerId]] = state;
});
this.setupBackendCheckboxForm(req.modules);
}
setupBackendCheckboxForm(modules) {
let supportedModules = {};
$.each(modules, (id, module) => {
if (this.knownBackendSupport[module]) {
supportedModules[id] = module;
}
});
if (Object.keys(supportedModules).length) {
this.backendSupportRelated = { ...this.backendSupportRelated, ...supportedModules };
let req = $.ajax({
context : this,
type : 'get',
url : this.icinga.config.baseUrl + '/icingadb/migrate/checkbox-state?showCompact'
});
req.done(this.setCheckboxState);
}
}
setCheckboxState(html, textStatus, req) {
let $form = this.Popup().find('.suggestion-area > #setAsBackendForm');
if (! $form.length) {
$form = $(html);
$form.attr('data-base-target', 'migrate-popup-backend-submit-blackhole');
$form.append('<div id="migrate-popup-backend-submit-blackhole"></div>');
this.Popup().find('.monitoring-migration-suggestions').before($form);
} else {
let $newForm = $(html);
$form.find('[name=backend]').prop('checked', $newForm.find('[name=backend]').is(':checked'));
}
this.showPopup();
}
addSuggestions(urls, type) {
var where;
if (type === 'monitoring') {
where = '.monitoring-migration-suggestions';
} else {
where = '.search-migration-suggestions';
}
const where = '.search-migration-suggestions';
var _this = this,
hasSuggestions = false,
@ -490,53 +334,21 @@
return toBeRemoved;
}
cleanupBackendForm() {
let $form = this.Popup().find('#setAsBackendForm');
if (! $form.length) {
return false;
}
let stillRelated = {};
$.each(this.backendSupportRelated, (id, module) => {
let $container = $('#' + id);
if ($container.length && $container.data('icingaModule') === module) {
stillRelated[id] = module;
}
});
this.backendSupportRelated = stillRelated;
if (Object.keys(stillRelated).length) {
return true;
}
return $form;
}
cleanupPopup() {
let toBeRemoved = this.cleanupSuggestions();
let hasBackendForm = this.cleanupBackendForm();
if (hasBackendForm !== true && this.Popup().find('li').length === toBeRemoved.length) {
if (this.Popup().find('li').length === toBeRemoved.length) {
this.hidePopup(() => {
// Let the transition finish first, looks cleaner
$.each(toBeRemoved, function (_, $suggestion) {
$suggestion.remove();
});
if (typeof hasBackendForm === 'object') {
hasBackendForm.remove();
}
});
} else {
$.each(toBeRemoved, function (_, $suggestion) {
$suggestion.remove();
});
if (typeof hasBackendForm === 'object') {
hasBackendForm.remove();
}
// Let showPopup() handle the automatic minimization in case all search suggestions have been removed
this.showPopup();
}
@ -593,49 +405,12 @@
}
}
setUrlMigrationReadyState(state) {
this.urlMigrationReadyState = state;
}
changeUrlMigrationReadyState(state) {
this.setUrlMigrationReadyState(state);
if (this.backendSupportReadyState !== false && this.searchMigrationReadyState !== false) {
this.searchMigrationReadyState = null;
this.backendSupportReadyState = null;
this.urlMigrationReadyState = null;
this.cleanupPopup();
}
}
setSearchMigrationReadyState(state) {
this.searchMigrationReadyState = state;
}
changeSearchMigrationReadyState(state) {
this.setSearchMigrationReadyState(state);
if (this.backendSupportReadyState !== false && this.urlMigrationReadyState !== false) {
this.searchMigrationReadyState = null;
this.backendSupportReadyState = null;
this.urlMigrationReadyState = null;
this.cleanupPopup();
}
}
setBackendSupportReadyState(state) {
this.backendSupportReadyState = state;
}
changeBackendSupportReadyState(state) {
this.setBackendSupportReadyState(state);
if (this.urlMigrationReadyState !== false && this.searchMigrationReadyState !== false) {
this.searchMigrationReadyState = null;
this.backendSupportReadyState = null;
this.urlMigrationReadyState = null;
this.cleanupPopup();
}
}
Popup() {