state save for long running processes between page load

relies on https://review.opendev.org/#/c/734699/10

Change-Id: I86ce5c2e7fc8615f5f4827b385b567842572590c
This commit is contained in:
Schiefelbein, Andrew 2020-06-12 13:55:46 -05:00
parent 530a94b6a3
commit 8d696a70a1
7 changed files with 55 additions and 38 deletions

View File

@ -19,8 +19,12 @@ import (
"opendev.org/airship/airshipctl/pkg/environment"
"opendev.org/airship/airshipctl/pkg/version"
"opendev.org/airship/airshipui/internal/configs"
)
// maintain the state of a potentially long running process
var runningRequests map[configs.WsSubComponentType]bool = make(map[configs.WsSubComponentType]bool)
// ctlPage struct is used for templated HTML
type ctlPage struct {
ClusterRows string
@ -28,6 +32,8 @@ type ctlPage struct {
CredentialRows string
Title string
Version string
Disabled string
ButtonText string
}
// client provides a library of functions that enable external programs (e.g. Airship UI) to perform airshipctl

View File

@ -21,6 +21,7 @@ import (
)
// HandleBaremetalRequest will flop between requests so we don't have to have them all mapped as function calls
// This will wait for the sub component to complete before responding. The assumption is this is an async request
func HandleBaremetalRequest(request configs.WsMessage) configs.WsMessage {
response := configs.WsMessage{
Type: configs.AirshipCTL,
@ -30,13 +31,16 @@ func HandleBaremetalRequest(request configs.WsMessage) configs.WsMessage {
var err error
var message string
switch request.SubComponent {
subComponent := request.SubComponent
switch subComponent {
case configs.GetDefaults:
response.HTML, err = getBaremetalHTML()
case configs.DocPull:
message, err = c.docPull()
case configs.GenerateISO:
// since this is long running cache it up
runningRequests[subComponent] = true
message, err = c.generateIso()
// now that we're done forget we did anything
delete(runningRequests, subComponent)
default:
err = fmt.Errorf("Subcomponent %s not found", request.SubComponent)
}
@ -61,8 +65,16 @@ func (c *client) generateIso() (string, error) {
}
func getBaremetalHTML() (string, error) {
return getHTML("./internal/integrations/ctl/templates/baremetal.html", ctlPage{
Title: "Baremetal",
Version: getAirshipCTLVersion(),
})
p := ctlPage{
Title: "Baremetal",
Version: getAirshipCTLVersion(),
ButtonText: "Generate ISO",
}
if _, ok := runningRequests[configs.GenerateISO]; ok {
p.Disabled = "disabled"
p.ButtonText = "In Progress"
}
return getHTML("./internal/integrations/ctl/templates/baremetal.html", p)
}

View File

@ -2,4 +2,4 @@
<p>Version: {{.Version}}</p>
<h2>Generate ISO</h2>
<button type="button" class="btn btn-info" id="GenIsoBtn" onclick="baremetalAction(this)" style="width: 150px;">Generate ISO</button>
<button type="button" class="btn btn-info" id="GenIsoBtn" onclick="baremetalAction(this)" style="width: 150px;" {{.Disabled}}>{{.ButtonText}}</button>

View File

@ -31,7 +31,7 @@ var upgrader = websocket.Upgrader{
}
// this is a way to allow for arbitrary messages to be processed by the backend
// most likely we will need to have sub components register with the system
// the message of a specifc component is shunted to that subsystem for further processing
// TODO: make this a dynamic registration of components
var functionMap = map[configs.WsRequestType]map[configs.WsComponentType]func(configs.WsMessage) configs.WsMessage{
configs.Electron: {

View File

@ -26,10 +26,11 @@ document.addEventListener("DOMContentLoaded", () => {
// Displays the alerts from the backend
function handleCTLResponse(json) { // eslint-disable-line no-unused-vars
let message = json["type"] + " " + json["component"] + " " + json["subComponent"] + " ";
if (json.hasOwnProperty("error")) {
showDismissableAlert("danger", json["error"], false);
showDismissableAlert("danger", message + json["error"], false);
} else {
showDismissableAlert("info", json["message"], false);
showDismissableAlert("info", message + json["message"], true);
}
}

View File

@ -34,20 +34,22 @@ if (document.addEventListener) {
// add dashboard links to Dropdown if present in $HOME/.airship/airshipui.json
function addServiceDashboards(json) { // eslint-disable-line no-unused-vars
for (let i = 0; i < json.length; i++) {
let cluster = json[i];
for (let j = 0; j < cluster.namespaces.length; j++) {
let namespace = cluster.namespaces[j];
for (let k = 0; k < namespace.dashboards.length; k++) {
let dash = namespace.dashboards[k];
let fqdn = "";
if (dash.fqdn === undefined) {
fqdn = `${dash.hostname}.${cluster.namespaces[j].name}.${cluster.baseFqdn}`
} else {
({ fqdn } = dash.fqdn);
if (json !== undefined) {
for (let i = 0; i < json.length; i++) {
let cluster = json[i];
for (let j = 0; j < cluster.namespaces.length; j++) {
let namespace = cluster.namespaces[j];
for (let k = 0; k < namespace.dashboards.length; k++) {
let dash = namespace.dashboards[k];
let fqdn = "";
if (dash.fqdn === undefined) {
fqdn = `${dash.hostname}.${cluster.namespaces[j].name}.${cluster.baseFqdn}`
} else {
({ fqdn } = dash.fqdn);
}
let url = `${dash.protocol}://${fqdn}:${dash.port}/${dash.path || ""}`;
addDashboard("DashDropdown", dash.name, url)
}
let url = `${dash.protocol}://${fqdn}:${dash.port}/${dash.path || ""}`;
addDashboard("DashDropdown", dash.name, url)
}
}
}
@ -56,11 +58,13 @@ function addServiceDashboards(json) { // eslint-disable-line no-unused-vars
// if any plugins (external executables) have a corresponding web dashboard defined,
// add them to the dropdown
function addPluginDashboards(json) { // eslint-disable-line no-unused-vars
for (let i = 0; i < json.length; i++) {
if (json[i].executable.autoStart && json[i].dashboard.fqdn !== undefined) {
let dash = json[i].dashboard;
let url = `${dash.protocol}://${dash.fqdn}:${dash.port}/${dash.path || ""}`;
addDashboard("PluginDropdown", json[i].name, url);
if (json !== undefined) {
for (let i = 0; i < json.length; i++) {
if (json[i].executable.autoStart && json[i].dashboard.fqdn !== undefined) {
let dash = json[i].dashboard;
let url = `${dash.protocol}://${dash.fqdn}:${dash.port}/${dash.path || ""}`;
addDashboard("PluginDropdown", json[i].name, url);
}
}
}
}
@ -91,12 +95,6 @@ function authenticate(json) { // eslint-disable-line no-unused-vars
view.src = json["url"];
}
function removeElement(id) { // eslint-disable-line no-unused-vars
if (document.contains(document.getElementById(id))) {
document.getElementById(id).remove();
}
}
// show a dismissable alert in the UI
// if 'fade' is set to true, the alert will fade out and disappear after 5s
function showDismissableAlert(alertLevel, msg, fade) { // eslint-disable-line no-unused-vars

View File

@ -75,11 +75,11 @@ function hanldleElectronMessages(json) {
authenticate(json["authentication"]);
} else {
authComplete();
}
if (json["plugins"] !== null) {
}
if (json.hasOwnProperty("plugins")) {
addPluginDashboards(json["plugins"]);
}
if (json["dashboards"] !== null) {
if (json.hasOwnProperty("dashboards")) {
addServiceDashboards(json["dashboards"]);
}
} else if (json["component"] === "authcomplete") {