luci-mod-network: split config migration into 2 steps

Problem with handling all migrations in 1 step is that uci.sections()
doesn't include changes queued using uci.callAdd() and uci.callSet().
That could result in unexpected behaviour and generating invalid
configs.

For the sake of simplicity and reliability use 2 steps migration. The
downside is that users may get prompted twice to migrate.

Reported-by: Hauke Mehrtens <hauke@hauke-m.de>
Fixes: 74be304e54 ("treewide: use "device" option in UCI "interface" sections")
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
Tested-by: Hauke Mehrtens <hauke@hauke-m.de>
This commit is contained in:
Rafał Miłecki 2021-05-29 17:19:02 +02:00
parent 79947af064
commit e7c9c63c65

View file

@ -317,11 +317,10 @@ return view.extend({
}); });
}, },
handleMigration: function(ev) { handleBridgeMigration: function(ev) {
var interfaces = this.interfaceBridgeWithIfnameSections();
var tasks = []; var tasks = [];
interfaces.forEach(function(ns) { this.interfaceBridgeWithIfnameSections().forEach(function(ns) {
var device_name = 'br-' + ns['.name']; var device_name = 'br-' + ns['.name'];
tasks.push(uci.callAdd('network', 'device', null, { tasks.push(uci.callAdd('network', 'device', null, {
@ -332,12 +331,33 @@ return view.extend({
tasks.push(uci.callSet('network', ns['.name'], { tasks.push(uci.callSet('network', ns['.name'], {
'type': '', 'type': '',
'ifname': '',
'device': device_name 'device': device_name
})); }));
}); });
return Promise.all(tasks)
.then(L.bind(ui.changes.init, ui.changes))
.then(L.bind(ui.changes.apply, ui.changes));
},
renderBridgeMigration: function() {
ui.showModal(_('Network bridge configuration migration'), [
E('p', _('The existing network configuration needs to be changed for LuCI to function properly.')),
E('p', _('Upon pressing "Continue", bridges configuration will be updated and the network will be restarted to apply the updated configuration.')),
E('div', { 'class': 'right' },
E('button', {
'class': 'btn cbi-button-action important',
'click': ui.createHandlerFn(this, 'handleBridgeMigration')
}, _('Continue')))
]);
},
handleIfnameMigration: function(ev) {
var tasks = [];
this.deviceWithIfnameSections().forEach(function(ds) { this.deviceWithIfnameSections().forEach(function(ds) {
tasks.push(uci.callSet('network', ds['.name'], { tasks.push(uci.add('network', ds['.name'], {
'ifname': '', 'ifname': '',
'ports': L.toArray(ds.ifname) 'ports': L.toArray(ds.ifname)
})); }));
@ -355,14 +375,14 @@ return view.extend({
.then(L.bind(ui.changes.apply, ui.changes)); .then(L.bind(ui.changes.apply, ui.changes));
}, },
renderMigration: function() { renderIfnameMigration: function() {
ui.showModal(_('Network bridge configuration migration'), [ ui.showModal(_('Network ifname configuration migration'), [
E('p', _('The existing network configuration needs to be changed for LuCI to function properly.')), E('p', _('The existing network configuration needs to be changed for LuCI to function properly.')),
E('p', _('Upon pressing "Continue", bridges configuration will be updated and the network will be restarted to apply the updated configuration.')), E('p', _('Upon pressing "Continue", ifname options will get renamed and the network will be restarted to apply the updated configuration.')),
E('div', { 'class': 'right' }, E('div', { 'class': 'right' },
E('button', { E('button', {
'class': 'btn cbi-button-action important', 'class': 'btn cbi-button-action important',
'click': ui.createHandlerFn(this, 'handleMigration') 'click': ui.createHandlerFn(this, 'handleIfnameMigration')
}, _('Continue'))) }, _('Continue')))
]); ]);
}, },
@ -370,11 +390,12 @@ return view.extend({
render: function(data) { render: function(data) {
var netifdVersion = (data[3] || '').match(/Version: ([^\n]+)/); var netifdVersion = (data[3] || '').match(/Version: ([^\n]+)/);
if (netifdVersion && netifdVersion[1] >= "2021-05-26" && if (netifdVersion && netifdVersion[1] >= "2021-05-26") {
(this.interfaceBridgeWithIfnameSections().length || if (this.interfaceBridgeWithIfnameSections().length)
this.deviceWithIfnameSections().length || return this.renderBridgeMigration();
this.interfaceWithIfnameSections().length)) else if (this.deviceWithIfnameSections().length || this.interfaceWithIfnameSections().length)
return this.renderMigration(); return this.renderIfnameMigration();
}
var dslModemType = data[0], var dslModemType = data[0],
netDevs = data[1], netDevs = data[1],