From 0c7f3331aff33567e01e0d9c0c63b9a1a16fbe14 Mon Sep 17 00:00:00 2001 From: Paul Spooren Date: Wed, 4 Mar 2020 22:36:22 -1000 Subject: [PATCH] luci-app-attendedsysupgrade: use new ASU API The API of ASU changed as it now uses a static `versions` JSON file. This moves the upgrade validation to the client site and simplifyies the server code. Build requests now use the unique `profile` withouth the need of sending the devices target. Also some XMLHttpRequests were replaced by the newer `fetch` function. Signed-off-by: Paul Spooren --- .../resources/attendedsysupgrade.js | 277 ++++++++---------- 1 file changed, 117 insertions(+), 160 deletions(-) diff --git a/applications/luci-app-attendedsysupgrade/root/www/luci-static/resources/attendedsysupgrade.js b/applications/luci-app-attendedsysupgrade/root/www/luci-static/resources/attendedsysupgrade.js index 2cf5cc6e1..9cfd1bc7a 100644 --- a/applications/luci-app-attendedsysupgrade/root/www/luci-static/resources/attendedsysupgrade.js +++ b/applications/luci-app-attendedsysupgrade/root/www/luci-static/resources/attendedsysupgrade.js @@ -58,21 +58,6 @@ function edit_packages() { show("#edit_packages"); } -// requests to the upgrade server -function server_request(path, callback) { - var request = new XMLHttpRequest(); - request.open("POST", data.url + "/" + path, true); - request.setRequestHeader("Content-type", "application/json"); - request.send(JSON.stringify(request_dict)); - request.onerror = function(e) { - set_status("danger", "upgrade server down") - show("#server_div"); - } - request.addEventListener('load', function(event) { - callback(request) - }); -} - // initial setup, get system information function setup() { ubus_call("rpc-sys", "packagelist", {}, "packages"); @@ -163,57 +148,74 @@ function set_status(type, message, loading, show_log) { if (loading) { loading_image = 'Loading '; } - if (show_log && data.log) { - message += '

Build log

' + if (data.buildlog_url && show_log) { + message += '

Build log

' } $("#status_box").innerHTML = loading_image + message; show("#status_box") } function upgrade_check() { - // Asks server for new firmware - // If data.upgrade_packages is set to true search for new package versions as well + var current_version = data.release.version.toLowerCase(); + var current_branch = current_version.split('.').slice(0, 2).join('.') + var candidates = [] hide("#status_box"); hide("#server_div"); set_status("info", "Searching for upgrades", true); - request_dict.distro = data.release.distribution; - request_dict.version = data.release.version; - request_dict.target = data.release.target; - request_dict.revision = data.release.revision; - request_dict.installed = data.packages; - request_dict.upgrade_packages = data.upgrade_packages - server_request("api/upgrade-check", upgrade_check_callback) -} + fetch(data.url + "/api/versions") + .then(response => response.json()) + .then(response => { + var branches = response["branches"] + for (i in branches) { + // handle snapshots in a special way - as always + if (current_version == "snapshot" && branches[i]["latest"] == "snapshot") { + candidates.unshift(branches[i]) + break + } + + if (current_version == branches[i]["latest"]) { + break + } + if (current_branch != branches[i]["name"]) { + branches[i]["warn_branch_jump"] = true + } + candidates.unshift(branches[i]) + if (current_branch == branches[i]["name"]) { + // don't offer branches older than the current + break + } + } -function upgrade_check_callback(request_text) { - var request_json = JSON.parse(request_text) + if (candidates.length > 0) { + var info_output = "

New release " + candidates[0].latest + " available

" + info_output += "Installed version: " + data.release.version + + // tell server the currently installed version + request_dict.current_version = request_dict.version; + // tell server what version to install + request_dict.version = candidates[0].latest; + // tell server to diff the requested packages with the default packages + // this allows to not automatically re-install default packages which + // where dropped in later releases + request_dict.diff_packages = true; + + set_status("success", info_output) + + if (data.advanced_mode == 1) { + show("#edit_button"); + } + var upgrade_button = $("#upgrade_button") + upgrade_button.value = "Request firmware"; + upgrade_button.style.display = "block"; + upgrade_button.disabled = false; + upgrade_button.onclick = upgrade_request; + + } else { + set_status("success", "No upgrades available") - // create simple output to tell user what's going to be upgrade (release/packages) - var info_output = "" - if (request_json.version) { - info_output += "

New release " + request_json.version + " available

" - info_output += "Installed version: " + data.release.version - request_dict.version = request_json.version; - } - if (request_json.upgrades) { - if (request_json.upgrades != {}) { - info_output += "

Package upgrades available

" - for (var upgrade in request_json.upgrades) { - info_output += "" + upgrade + ": " + request_json.upgrades[upgrade][1] + " to " + request_json.upgrades[upgrade][0] + "
" } - } - } - data.packages = request_json.packages - set_status("success", info_output) + }); - if (data.advanced_mode == 1) { - show("#edit_button"); - } - var upgrade_button = $("#upgrade_button") - upgrade_button.value = "Request firmware"; - upgrade_button.style.display = "block"; - upgrade_button.disabled = false; - upgrade_button.onclick = upgrade_request; } function upgrade_request() { @@ -224,37 +226,39 @@ function upgrade_request() { hide("#edit_button"); hide("#keep_container"); - // remove "installed" entry as unused by build requests - delete request_dict.installed // add board info to let server determine profile - request_dict.board_name = data.board_name - request_dict.board = data.board_name - request_dict.model = data.model + request_dict.profile = data.board_name if (data.edit_packages == true) { request_dict.packages = $("#edit_packages").value.split("\n") } else { - request_dict.packages = data.packages; + request_dict.packages = Object.keys(data.packages); } - server_request("api/upgrade-request", upgrade_request_callback) + server_request() } -function upgrade_request_callback(request) { - // ready to download - var request_json = JSON.parse(request) - data.files = request_json.files - data.sysupgrade = request_json.sysupgrade - data.log = request_json.log - - var info_output = '

Firmware created

Created file: ' + data.sysupgrade + '

' - set_status("success", info_output, false, true); - - show("#keep_container"); - var upgrade_button = $("#upgrade_button") - upgrade_button.disabled = false; - upgrade_button.style.display = "block"; - upgrade_button.value = "Flash firmware"; - upgrade_button.onclick = download_image; +function upgrade_request_callback(response) { + var sysupgrade_file = ""; + console.log(response) + for (i in response.images) { + if (response.images[i].type == "sysupgrade") { + sysupgrade_file = response.images[i].name; + } + } + if (sysupgrade_file != "") { + data.sysupgrade_url = data.url + '/store/' + response.bin_dir + '/' + sysupgrade_file + var info_output = '

Firmware created

Created file: ' + sysupgrade_file + '

' + set_status("success", info_output, false, true); + + show("#keep_container"); + var upgrade_button = $("#upgrade_button") + upgrade_button.disabled = false; + upgrade_button.style.display = "block"; + upgrade_button.value = "Flash firmware"; + upgrade_button.onclick = download_image; + } else { + set_status("danger", "Firmware build successfull but device not sysupgrade compatible!") + } } function flash_image() { @@ -323,7 +327,7 @@ function download_image() { hide("#keep_container"); hide("#upgrade_button"); var download_request = new XMLHttpRequest(); - download_request.open("GET", data.url + data.files + data.sysupgrade); + download_request.open("GET", data.sysupgrade_url); download_request.responseType = "arraybuffer"; download_request.onload = function() { @@ -338,90 +342,43 @@ function download_image() { download_request.send(); } -function server_request(path, callback) { - var request_json; - var request = new XMLHttpRequest(); - request.open("POST", data.url + "/" + path, true); - request.setRequestHeader("Content-type", "application/json"); - request.send(JSON.stringify(request_dict)); - request.onerror = function(e) { - set_status("danger", "Upgrade server down or could not connect") - show("#server_div"); - } - request.addEventListener('load', function(event) { - var request_text = request.responseText; - if (request.status === 200) { - callback(request_text) - - } else if (request.status === 202) { - var imagebuilder = request.getResponseHeader("X-Imagebuilder-Status"); - if (imagebuilder === "queue") { - // in queue - var queue = request.getResponseHeader("X-Build-Queue-Position"); - set_status("info", "In build queue position " + queue, true) - console.log("queued"); - } else if (imagebuilder === "building") { - set_status("info", "Building image", true); - console.log("building"); - } else { - // fallback if for some reasons the headers are missing e.g. browser blocks access - set_status("info", "Processing request", true); - console.log(imagebuilder) +function server_request() { + fetch(data.url + "/api/build", { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(request_dict) + }) + .then(response => { + switch (response.status) { + case 200: + response.json() + .then(response => { + upgrade_request_callback(response) + }); + break; + case 202: + set_status("info", "Processing request", true); + setTimeout(function() { + server_request() + }, 5000) + break; + case 400: // bad request + case 422: // bad package + case 500: // build failed + console.log('error (' + response.status + ')'); + response.json() + .then(response => { + if (response.buildlog) { + data.buildlog_url = data.url + '/' + response.bin_dir + '/buildlog.txt'; + } + set_status("danger", response.message); + }); + break; } - setTimeout(function() { - server_request(path, callback) - }, 5000) - - } else if (request.status === 204) { - // no upgrades available - set_status("success", "No upgrades available") - - } else if (request.status === 400) { - // bad request - request_json = JSON.parse(request_text) - set_status("danger", request_json.error) - - } else if (request.status === 409) { - // bad request - request_json = JSON.parse(request_text) - data.log = request_json.log - set_status("danger", "Incompatible package selection. See build log for details", false, true) - - } else if (request.status === 412) { - // this is a bit generic - set_status("danger", "Unsupported device, release, target, subtraget or board") - - } else if (request.status === 413) { - set_status("danger", "No firmware created due to image size. Try again with less packages selected.") - - } else if (request.status === 422) { - var package_missing = request.getResponseHeader("X-Unknown-Package"); - set_status("danger", "Unknown package in request: " + package_missing + "") - } else if (request.status === 500) { - request_json = JSON.parse(request_text) - - var error_box_content = "Internal server error
" - error_box_content += request_json.error - if (request_json.log != undefined) { - data.log = request_json.log - } - set_status("danger", error_box_content, false, true) - - } else if (request.status === 501) { - set_status("danger", "No sysupgrade file produced, may not supported by model.") - } else if (request.status === 502) { - // python part offline - set_status("danger", "Server down for maintenance") - setTimeout(function() { - server_request(path, callback) - }, 30000) - } else if (request.status === 503) { - set_status("danger", "Server overloaded") - setTimeout(function() { - server_request(path, callback) - }, 30000) - } - }); + }); } + request_dict = {} document.onload = setup() -- 2.25.1