summaryrefslogtreecommitdiffhomepage
path: root/applications/luci-app-attendedsysupgrade/htdocs/luci-static/resources/view/attendedsysupgrade
diff options
context:
space:
mode:
authorPaul Spooren <mail@aparcar.org>2021-08-29 00:37:31 -1000
committerPaul Spooren <mail@aparcar.org>2021-08-30 10:20:12 -1000
commitf799d550b6389baee5b388eefe638ba9a690f4c5 (patch)
tree220782d61b4357b50d4e8b94a0abef3b6e234381 /applications/luci-app-attendedsysupgrade/htdocs/luci-static/resources/view/attendedsysupgrade
parentab2f8b8b04d7a9b048e2c2bf92d7eb043d2d27b1 (diff)
luci-app-attendedsysupgrade: support revision checks
SNAPSHOTS are not real releases and therefore the app always offers an upgrade, even if running the latest build. To prevent that all SNAPSHOTS now check for the running revision and if a newer one is available. Also do a bunch of refactoring based on JavaScript I learned over the last week. Signed-off-by: Paul Spooren <mail@aparcar.org>
Diffstat (limited to 'applications/luci-app-attendedsysupgrade/htdocs/luci-static/resources/view/attendedsysupgrade')
-rw-r--r--applications/luci-app-attendedsysupgrade/htdocs/luci-static/resources/view/attendedsysupgrade/overview.js734
1 files changed, 382 insertions, 352 deletions
diff --git a/applications/luci-app-attendedsysupgrade/htdocs/luci-static/resources/view/attendedsysupgrade/overview.js b/applications/luci-app-attendedsysupgrade/htdocs/luci-static/resources/view/attendedsysupgrade/overview.js
index fc179212b1..b148e793b2 100644
--- a/applications/luci-app-attendedsysupgrade/htdocs/luci-static/resources/view/attendedsysupgrade/overview.js
+++ b/applications/luci-app-attendedsysupgrade/htdocs/luci-static/resources/view/attendedsysupgrade/overview.js
@@ -9,382 +9,412 @@
'require dom';
var callPackagelist = rpc.declare({
- object: 'rpc-sys',
- method: 'packagelist',
+ object: 'rpc-sys',
+ method: 'packagelist',
});
var callSystemBoard = rpc.declare({
- object: 'system',
- method: 'board'
+ object: 'system',
+ method: 'board'
});
var callUpgradeStart = rpc.declare({
- object: 'rpc-sys',
- method: 'upgrade_start',
- params: ["keep"]
+ object: 'rpc-sys',
+ method: 'upgrade_start',
+ params: ["keep"]
});
function get_branch(version) {
- // determine branch of a version
- // SNAPSHOT -> SNAPSHOT
- // 21.02-SNAPSHOT -> 21.02
- // 21.02.0-rc1 -> 21.02
- // 19.07.8 -> 19.07
- return version.replace("-SNAPSHOT", "").split(".").slice(0, 2).join(".");
+ // determine branch of a version
+ // SNAPSHOT -> SNAPSHOT
+ // 21.02-SNAPSHOT -> 21.02
+ // 21.02.0-rc1 -> 21.02
+ // 19.07.8 -> 19.07
+ return version.replace("-SNAPSHOT", "").split(".").slice(0, 2).join(".");
+}
+
+function get_revision_count(revision) {
+ return parseInt(revision.substring(1).split("-")[0])
+}
+
+function error_api_connect(response) {
+ console.log(response)
+ ui.showModal(_('Error connecting to upgrade server'), [
+ E('p', {}, _(`Could not reach API at "${response.url}. Please try again later.`)),
+ E('pre', {}, response.responseText),
+ E('div', {
+ 'class': 'right'
+ }, [
+ E('div', {
+ 'class': 'btn',
+ 'click': ui.hideModal
+ }, _('Close'))
+ ])
+ ]);
}
function install_sysupgrade(url, keep, sha256) {
- displayStatus("notice spinning", E('p', _('Downloading firmware from server to browser')));
- request.get(url, {
- headers: {
- 'Content-Type': 'application/x-www-form-urlencoded'
- },
- responseType: 'blob'
- })
- .then(response => {
- var form_data = new FormData();
- form_data.append("sessionid", rpc.getSessionID());
- form_data.append("filename", "/tmp/firmware.bin");
- form_data.append("filemode", 600);
- form_data.append("filedata", response.blob());
-
- displayStatus("notice spinning", E('p', _('Uploading firmware from browser to device')));
- request.get(L.env.cgi_base + "/cgi-upload", {
- method: 'PUT',
- content: form_data
- })
- .then(response => response.json())
- .then(response => {
- if (response.sha256sum != sha256) {
- displayStatus("warning", [
- E('b', _('Wrong checksum')),
- E('p', _('Error during download of firmware. Please try again')),
- E('div', {
- 'class': 'btn',
- 'click': ui.hideModal
- }, _('Close'))
- ]);
- } else {
- displayStatus('warning spinning', E('p', _('Installing the sysupgrade. Do not unpower device!')));
- L.resolveDefault(callUpgradeStart(keep), {}).then(response => {
- if (keep) {
- ui.awaitReconnect(window.location.host);
- } else {
- ui.awaitReconnect('192.168.1.1', 'openwrt.lan');
- }
- });
- }
- });
- });
+ displayStatus("notice spinning", E('p', _('Downloading firmware from server to browser')));
+ request.get(url, {
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded'
+ },
+ responseType: 'blob'
+ })
+ .then(response => {
+ var form_data = new FormData();
+ form_data.append("sessionid", rpc.getSessionID());
+ form_data.append("filename", "/tmp/firmware.bin");
+ form_data.append("filemode", 600);
+ form_data.append("filedata", response.blob());
+
+ displayStatus("notice spinning", E('p', _('Uploading firmware from browser to device')));
+ request.get(`${L.env.cgi_base}/cgi-upload`, {
+ method: 'PUT',
+ content: form_data
+ })
+ .then(response => response.json())
+ .then(response => {
+ if (response.sha256sum != sha256) {
+ displayStatus("warning", [
+ E('b', _('Wrong checksum')),
+ E('p', _('Error during download of firmware. Please try again')),
+ E('div', {
+ 'class': 'btn',
+ 'click': ui.hideModal
+ }, _('Close'))
+ ]);
+ } else {
+ displayStatus('warning spinning', E('p', _('Installing the sysupgrade. Do not unpower device!')));
+ L.resolveDefault(callUpgradeStart(keep), {}).then(response => {
+ if (keep) {
+ ui.awaitReconnect(window.location.host);
+ } else {
+ ui.awaitReconnect('192.168.1.1', 'openwrt.lan');
+ }
+ });
+ }
+ });
+ });
}
function request_sysupgrade(server_url, data) {
- var res, req;
-
- if (data.request_hash) {
- req = request.get(server_url + "/api/build/" + data.request_hash)
- } else {
- req = request.post(server_url + "/api/build", {
- profile: data.board_name,
- target: data.target,
- version: data.version,
- packages: data.packages,
- diff_packages: true,
- })
- }
-
- req.then(response => {
- switch (response.status) {
- case 200:
- var res = response.json()
- var image;
- for (image of res.images) {
- if (image.type == "sysupgrade") {
- break;
- }
- }
- if (image.name != undefined) {
- var sysupgrade_url = server_url + "/store/" + res.bin_dir + "/" + image.name;
-
- var keep = E('input', {
- type: 'checkbox'
- })
- keep.checked = true;
-
- var fields = [
- _('Version'), res.version_number + ' ' + res.version_code,
- _('File'), E('a', {
- 'href': sysupgrade_url
- }, image.name),
- _('SHA256'), image.sha256,
- _('Build Date'), res.build_at,
- _('Target'), res.target,
- ];
-
- var table = E('div', {
- 'class': 'table'
- });
-
- for (var i = 0; i < fields.length; i += 2) {
- table.appendChild(E('div', {
- 'class': 'tr'
- }, [
- E('div', {
- 'class': 'td left',
- 'width': '33%'
- }, [fields[i]]),
- E('div', {
- 'class': 'td left'
- }, [(fields[i + 1] != null) ? fields[i + 1] : '?'])
- ]));
- }
-
- var modal_body = [
- table,
- E('p', {}, E('label', {
- 'class': 'btn'
- }, [
- keep, ' ', _('Keep settings and retain the current configuration')
- ])),
- E('div', {
- 'class': 'right'
- }, [
- E('div', {
- 'class': 'btn',
- 'click': ui.hideModal
- }, _('Cancel')),
- ' ',
- E('div', {
- 'class': 'btn cbi-button-action',
- 'click': function() {
- install_sysupgrade(sysupgrade_url, keep.checked, image.sha256)
- }
- }, _('Install Sysupgrade'))
- ])
- ]
-
- ui.showModal(_('Successfully created sysupgrade image'), modal_body);
- }
-
- break;
- case 202:
- res = response.json()
- data.request_hash = res.request_hash;
-
- if ("queue_position" in res)
- displayStatus("notice spinning", E('p', _('Request in build queue position %d'.format(res.queue_position))));
- else
- displayStatus("notice spinning", E('p', _('Building firmware sysupgrade image')));
-
- setTimeout(function() {
- request_sysupgrade(server_url, data);
- }, 5000);
- break;
- case 400: // bad request
- case 422: // bad package
- case 500: // build failed
- res = response.json()
- var body = [
- E('p', {}, res.detail),
- E('p', {}, _("Please report the error message and request")),
- E('b', {}, _("Request to server:")),
- E('pre', {}, JSON.stringify(data, null, 4)),
-
- ]
-
- if (res.stdout) {
- body.push(E('b', {}, "STDOUT:"))
- body.push(E('pre', {}, res.stdout))
-
- }
-
- if (res.stderr) {
- body.push(E('b', {}, "STDERR:"))
- body.push(E('pre', {}, res.stderr))
-
- }
-
- body = body.concat([
- E('div', {
- 'class': 'right'
- }, [
- E('div', {
- 'class': 'btn',
- 'click': ui.hideModal
- }, _('Close'))
- ])
- ]);
- ui.showModal(_('Error building the sysupgrade'), body);
- break;
- }
- });
+ var res, req;
+
+ if (data.request_hash) {
+ req = request.get(`${server_url}/api/v1/build/${data.request_hash}`)
+ } else {
+ req = request.post(`${server_url}/api/v1/build`, {
+ profile: data.board_name,
+ target: data.target,
+ version: data.version,
+ packages: data.packages,
+ diff_packages: true,
+ })
+ }
+
+ req.then(response => {
+ switch (response.status) {
+ case 200:
+ res = response.json()
+ var image;
+ for (image of res.images) {
+ if (image.type == "sysupgrade") {
+ break;
+ }
+ }
+ if (image.name != undefined) {
+ var sysupgrade_url = `${server_url}/store/${res.bin_dir}/${image.name}`;
+
+ var keep = E('input', {
+ type: 'checkbox'
+ })
+ keep.checked = true;
+
+ var fields = [
+ _('Version'), `${res.version_number} ${res.version_code}`,
+ _('File'), E('a', {
+ 'href': sysupgrade_url
+ }, image.name),
+ _('SHA256'), image.sha256,
+ _('Build Date'), res.build_at,
+ _('Target'), res.target,
+ ];
+
+ var table = E('div', {
+ 'class': 'table'
+ });
+
+ for (var i = 0; i < fields.length; i += 2) {
+ table.appendChild(E('div', {
+ 'class': 'tr'
+ }, [
+ E('div', {
+ 'class': 'td left',
+ 'width': '33%'
+ }, [fields[i]]),
+ E('div', {
+ 'class': 'td left'
+ }, [(fields[i + 1] != null) ? fields[i + 1] : '?'])
+ ]));
+ }
+
+ var modal_body = [
+ table,
+ E('p', {}, E('label', {
+ 'class': 'btn'
+ }, [
+ keep, ' ', _('Keep settings and retain the current configuration')
+ ])),
+ E('div', {
+ 'class': 'right'
+ }, [
+ E('div', {
+ 'class': 'btn',
+ 'click': ui.hideModal
+ }, _('Cancel')),
+ ' ',
+ E('div', {
+ 'class': 'btn cbi-button-action',
+ 'click': function() {
+ install_sysupgrade(sysupgrade_url, keep.checked, image.sha256)
+ }
+ }, _('Install Sysupgrade'))
+ ])
+ ]
+
+ ui.showModal(_('Successfully created sysupgrade image'), modal_body);
+ }
+
+ break;
+ case 202:
+ res = response.json()
+ data.request_hash = res.request_hash;
+
+ if ("queue_position" in res)
+ displayStatus("notice spinning", E('p', _('Request in build queue position %d'.format(res.queue_position))));
+ else
+ displayStatus("notice spinning", E('p', _('Building firmware sysupgrade image')));
+
+ setTimeout(function() {
+ request_sysupgrade(server_url, data);
+ }, 5000);
+ break;
+ case 400: // bad request
+ case 422: // bad package
+ case 500: // build failed
+ res = response.json()
+ var body = [
+ E('p', {}, res.detail),
+ E('p', {}, _("Please report the error message and request")),
+ E('b', {}, _("Request to server:")),
+ E('pre', {}, JSON.stringify(data, null, 4)),
+
+ ]
+
+ if (res.stdout) {
+ body.push(E('b', {}, "STDOUT:"))
+ body.push(E('pre', {}, res.stdout))
+
+ }
+
+ if (res.stderr) {
+ body.push(E('b', {}, "STDERR:"))
+ body.push(E('pre', {}, res.stderr))
+
+ }
+
+ body = body.concat([
+ E('div', {
+ 'class': 'right'
+ }, [
+ E('div', {
+ 'class': 'btn',
+ 'click': ui.hideModal
+ }, _('Close'))
+ ])
+ ]);
+ ui.showModal(_('Error building the sysupgrade'), body);
+ break;
+ }
+ });
}
-function check_sysupgrade(server_url, current_version, target, board_name, packages) {
- displayStatus("notice spinning", E('p', _('Searching for an available sysupgrade')));
- var current_branch = get_branch(current_version);
- var advanced_mode = uci.get_first('attendedsysupgrade', 'client', 'advanced_mode') || 0;
- var candidates = [];
-
- request.get(server_url + "/json/latest.json", {
- timeout: 8000
- })
- .then(response => response.json())
- .then(response => {
- if (current_version == "SNAPSHOT") {
- candidates.push("SNAPSHOT");
- } else {
- for (let version of response["latest"]) {
- var branch = get_branch(version);
-
- // already latest version installed
- if (current_version == version) {
- break;
- }
-
- // skip branch upgrades outside the advanced mode
- if (current_branch != branch && advanced_mode == 0) {
- continue;
- }
-
- candidates.unshift(version);
-
- // don't offer branches older than the current
- if (current_branch == branch) {
- break;
- }
- }
- }
- if (candidates.length) {
- var m, s, o;
-
- var mapdata = {
- request: {
- board_name: board_name,
- target: target,
- version: candidates[0],
- packages: Object.keys(packages).sort(),
- }
- }
-
- m = new form.JSONMap(mapdata, '');
-
- s = m.section(form.NamedSection, 'request', 'example', '',
- 'Use defaults for the safest update');
- o = s.option(form.ListValue, 'version', 'Select firmware version');
- for (let candidate of candidates) {
- o.value(candidate, candidate);
- }
-
- if (advanced_mode == 1) {
- o = s.option(form.Value, 'board_name', 'Board Name / Profile');
- o = s.option(form.DynamicList, 'packages', 'Packages');
- }
-
-
- m.render()
- .then(function(form_rendered) {
- ui.showModal(_('New upgrade available'), [
- form_rendered,
- E('div', {
- 'class': 'right'
- }, [
- E('div', {
- 'class': 'btn',
- 'click': ui.hideModal
- }, _('Cancel')),
- ' ',
- E('div', {
- 'class': 'btn cbi-button-action',
- 'click': function() {
- m.save().then(foo => {
- request_sysupgrade(
- server_url, mapdata.request
- )
- });
- }
- }, _('Request Sysupgrade'))
- ])
- ]);
- });
- } else {
- ui.showModal(_('No upgrade available'), [
- E('p', {}, _("The device runs the latest firmware version")),
- E('div', {
- 'class': 'right'
- }, [
- E('div', {
- 'class': 'btn',
- 'click': ui.hideModal
- }, _('Close'))
- ])
- ]);
- }
- })
- .catch(error => {
- ui.showModal(_('Error connecting to upgrade server'), [
- E('p', {}, _('Could not reach API at "%s". Please try again later.'.format(server_url))),
- E('pre', {}, error),
- E('div', {
- 'class': 'right'
- }, [
- E('div', {
- 'class': 'btn',
- 'click': ui.hideModal
- }, _('Close'))
- ])
- ]);
- });
+async function check_sysupgrade(server_url, system_board, packages) {
+ var {
+ board_name
+ } = system_board;
+ var {
+ target,
+ version,
+ revision
+ } = system_board.release;
+ var current_branch = get_branch(version);
+ var advanced_mode = uci.get_first('attendedsysupgrade', 'client', 'advanced_mode') || 0;
+ var candidates = [];
+ var response;
+
+ displayStatus("notice spinning", E('p', _(`Searching for an available sysupgrade of ${version} - ${revision}`)));
+
+ if (version.endsWith("SNAPSHOT")) {
+ response = await request.get(`${server_url}/api/v1/revision/${version}/${target}`)
+ if (!response.ok) {
+ error_api_connect(response);
+ return;
+ }
+
+ const remote_revision = response.json().revision;
+
+ if (get_revision_count(revision) < get_revision_count(remote_revision)) {
+ candidates.push(version);
+ }
+ } else {
+ response = await request.get(`${server_url}/api/overview`, {
+ timeout: 8000
+ });
+
+ if (!response.ok) {
+ error_api_connect(response);
+ return;
+ }
+
+ const latest = response.json().latest
+
+ for (let remote_version of latest) {
+ var remote_branch = get_branch(remote_version);
+
+ // already latest version installed
+ if (version == remote_version) {
+ break;
+ }
+
+ // skip branch upgrades outside the advanced mode
+ if (current_branch != remote_branch && advanced_mode == 0) {
+ continue;
+ }
+
+ candidates.unshift(remote_version);
+
+ // don't offer branches older than the current
+ if (current_branch == remote_branch) {
+ break;
+ }
+ }
+ }
+
+ if (candidates.length) {
+ var m, s, o;
+
+ var mapdata = {
+ request: {
+ board_name: board_name,
+ target: target,
+ version: candidates[0],
+ packages: Object.keys(packages).sort(),
+ }
+ }
+
+ m = new form.JSONMap(mapdata, '');
+
+ s = m.section(form.NamedSection, 'request', 'example', '',
+ 'Use defaults for the safest update');
+ o = s.option(form.ListValue, 'version', 'Select firmware version');
+ for (let candidate of candidates) {
+ o.value(candidate, candidate);
+ }
+
+ if (advanced_mode == 1) {
+ o = s.option(form.Value, 'board_name', 'Board Name / Profile');
+ o = s.option(form.DynamicList, 'packages', 'Packages');
+ }
+
+
+ m.render()
+ .then(function(form_rendered) {
+ ui.showModal(_('New upgrade available'), [
+ form_rendered,
+ E('div', {
+ 'class': 'right'
+ }, [
+ E('div', {
+ 'class': 'btn',
+ 'click': ui.hideModal
+ }, _('Cancel')),
+ ' ',
+ E('div', {
+ 'class': 'btn cbi-button-action',
+ 'click': function() {
+ m.save().then(foo => {
+ request_sysupgrade(
+ server_url, mapdata.request
+ )
+ });
+ }
+ }, _('Request Sysupgrade'))
+ ])
+ ]);
+ });
+ } else {
+ ui.showModal(_('No upgrade available'), [
+ E('p', {}, _(`The device runs the latest firmware version ${version} - ${revision}`)),
+ E('div', {
+ 'class': 'right'
+ }, [
+ E('div', {
+ 'class': 'btn',
+ 'click': ui.hideModal
+ }, _('Close'))
+ ])
+ ]);
+ }
}
function displayStatus(type, content) {
- if (type) {
- var message = ui.showModal('', '');
+ if (type) {
+ var message = ui.showModal('', '');
- message.classList.add('alert-message');
- DOMTokenList.prototype.add.apply(message.classList, type.split(/\s+/));
+ message.classList.add('alert-message');
+ DOMTokenList.prototype.add.apply(message.classList, type.split(/\s+/));
- if (content)
- dom.content(message, content);
- } else {
- ui.hideModal();
- }
+ if (content)
+ dom.content(message, content);
+ } else {
+ ui.hideModal();
+ }
}
return view.extend({
- load: function() {
- return Promise.all([
- L.resolveDefault(callPackagelist(), {}),
- L.resolveDefault(callSystemBoard(), {}),
- uci.load('attendedsysupgrade')
- ]);
- },
- render: function(res) {
- var packages = res[0].packages;
- var current_version = res[1].release.version;
- var target = res[1].release.target;
- var board_name = res[1].board_name;
- var auto_search = uci.get_first('attendedsysupgrade', 'client', 'auto_search') || 1;
- var server_url = uci.get_first('attendedsysupgrade', 'server', 'url');
-
- var view = [
- E('h2', _("Attended Sysupgrade")),
- E('p', _('The attended sysupgrade service allows to easily upgrade vanilla and custom firmware images.')),
- E('p', _('This is done by building a new firmware on demand via an online service.'))
- ];
-
- if (auto_search == 1) {
- check_sysupgrade(server_url, current_version, target, board_name, packages)
- }
-
- view.push(E('p', {
- 'class': 'btn cbi-button-positive',
- 'click': function() {
- check_sysupgrade(server_url, current_version, target, board_name, packages)
- }
- }, _('Search for sysupgrade')));
-
- return view;
- },
+ load: function() {
+ return Promise.all([
+ L.resolveDefault(callPackagelist(), {}),
+ L.resolveDefault(callSystemBoard(), {}),
+ uci.load('attendedsysupgrade')
+ ]);
+ },
+ render: function(res) {
+ var packages = res[0].packages;
+ var system_board = res[1];
+ var auto_search = uci.get_first('attendedsysupgrade', 'client', 'auto_search') || 1;
+ var server_url = uci.get_first('attendedsysupgrade', 'server', 'url');
+
+ var view = [
+ E('h2', _("Attended Sysupgrade")),
+ E('p', _('The attended sysupgrade service allows to easily upgrade vanilla and custom firmware images.')),
+ E('p', _('This is done by building a new firmware on demand via an online service.'))
+ ];
+
+ if (auto_search == 1) {
+ check_sysupgrade(server_url, system_board, packages)
+ }
+
+ view.push(E('p', {
+ 'class': 'btn cbi-button-positive',
+ 'click': function() {
+ check_sysupgrade(server_url, system_board, packages)
+ }
+ }, _('Search for sysupgrade')));
+
+ return view;
+ },
});