Think of presenting the resource usage for customers.
In this document:
This development step updates the presentation logic with some UI widgets that show to customers resource consumption provided by the APS counters you have developed in the previous step. When opening the view with the list of resources, a customer will see the newest total resource consumption. Besides, the customer must be able to demand the update of those data.
Continue your demo project from the previous step.
Compared with the respective input file, the new ui/servers.js
file must present the resource counters
by means of the following updates:
The following steps create the new script.
Use the following script structure:
define([
"dojo/_base/declare",
"dojo/when",
"dojox/mvc/getStateful",
"dojox/mvc/at",
"dojo/_base/array",
"aps/View",
"aps/ResourceStore",
"aps/xhr",
"./displayError"
], function (
declare,
when,
getStateful,
at,
arr,
View,
Store,
xhr,
displayError
) {
var page, grid, self, contextId;
return declare(View, {
init: function() {
self = this; // Refer to the declared View object
/* Initialize data only the first time this view is called
after the base page is loaded or re-loaded.
Define widgets and sync them with the data models.
This method is missed in all subsequent cases when the view is called. */
},
onContext: function(context) {
/* Perform some actions with data before visualizing widgets. */
},
onHide: function() {
/* Performs some actions on leaving the view for another view. */
}
});
});
In the init
method, define the data sources:
self = this;
/* Create the data store for VPSes */
var vpsStore = new Store({
apsType: "http://aps-standard.org/samples/counters/vps/1.0",
target: "/aps/2/resources/"
});
/* Initialize a model to collect resource usage */
self.usageModel = getStateful({
"cpu": { "limit": 0, "usage": 0 },
"ram": { "limit": 0, "usage": 0 },
"disk": { "limit": 0, "usage": 0 }
});
Leave the handler for the New and Delete buttons the same as they are in the input package:
/* Handler for the *New* button */
var add = function() {
/* Start the process of creating a VPS by going to the first screen */
aps.apsc.gotoView("server-new-1");
};
/* Handler for the *Delete* button */
var remove = function() {
var btn = this;
/* Get confirmation from the user for the delete operation */
if (!confirm("Are you sure you want delete VPSes?")) {
btn.cancel();
return;
}
var sel = grid.get("selectionArray");
var counter = sel.length;
/* Clear the current messages on the screen */
page.get("messageList").removeAll();
sel.forEach(function(vpsId){
console.log("I'm trying to delete VPS with id = [" + vpsId + "]");
/* Remove the VPS from the APS controller DB */
when(vpsStore.remove(vpsId),
/* If success, process the next VPS until the list is empty */
function(){
console.log("VPS with id = [" + vpsId + "] removed");
sel.splice(sel.indexOf(vpsId),1);
grid.refresh();
if (--counter === 0) { btn.cancel(); }
},
/* If failure, call the error handler */
function(e){
displayError(e);
if (--counter === 0) { btn.cancel(); }
}
);
});
};
Define the handler for the Refresh button:
var refresh = function() {
xhr(
"/aps/2/resources/" + contextId + "/resourceCounting",
{ method: "GET", handleAs: "json" }
).then(function() {
return xhr(
"/aps/2/resources/" + contextId,
{ method: "GET", handleAs: "text" }
);
}).then(function(mgmtContext) {
self.usageModel.set("cpu", mgmtContext.cpuUsageTotal);
self.usageModel.set("ram", mgmtContext.memoryUsageTotal);
self.usageModel.set("disk", mgmtContext.diskUsageTotal);
grid.refresh();
});
};
The handler performs the following actions one by one:
resourceCounting
method.Define the methods that change the state of VPSes - handlers for the Start and Stop buttons
function changeState(state, btn) {
var sel = grid.get("selectionArray"),
counter = sel.length;
/* Clear the current messages on the screen */
page.get("messageList").removeAll();
arr.forEach(sel, function(vpsId) {
console.log("I'm trying to change state of VPS with id = [" + vpsId + "]");
/* Save the VPS state property */
when(
xhr(
"/aps/2/resources/" + vpsId + "/" + state,
{ method: "GET", handleAs: "text" }
),
/* If success, process the next VPS until the list is empty */
function() {
console.log("State of VPS with id = [" + vpsId + "] changed");
sel.splice(sel.indexOf(vpsId),1);
grid.refresh();
if (--counter === 0) { btn.cancel(); } /* Remove busy state for button */
},
/* If failure, call the error handler */
function(e) {
displayError(e);
if (--counter === 0) { btn.cancel(); }
}
); // End of when();
});
}
/* Handler for the *Stop* button */
var stop = function() {
changeState("stop", this);
};
/* Handler for the *Start* button */
var start = function() {
changeState("start", this);
};
Define and return the hierarchy of widgets. Along with the grid used in the input package, define the list of tiles showing the resource counters.
return [
["aps/Grid", {
id: this.genId("srv_grid"),
store: vpsStore,
selectionMode: "multiple",
apsResourceViewId: "server-edit",
noDataText: "No servers provisioned",
noEntriesFoundText: "No servers meet your search criteria",
columns: [{
field: "name",
name: "Name",
type: "resourceName",
filter: true
}, {
field: "hardware.memory",
name: "RAM",
title: "RAM",
type: "integer",
filter: true
}, {
field: "hardware.diskspace",
name: "Disk Space",
title: "Disk",
type: "integer",
filter: true
}, {
field: "hardware.CPU.number",
name: "CPU",
type: "integer",
filter: true
}, {
field: "platform.OS.name",
name: "OS",
filter: true
}, {
field: "state",
name: "State",
filter: true
}]}, [
["aps/Toolbar", [
["aps/ToolbarButton", {
id: "srv_new",
iconClass:"fa-plus",
type: "primary",
label: "New",
onClick: add
}],
["aps/ToolbarButton", {
id: "srv_start",
iconClass:"fa-play",
type: "success",
label: "Start",
requireItems: true,
onClick: start
}],
["aps/ToolbarButton", {
id: "srv_stop",
iconClass:"fa-pause",
type: "warning",
label: "Stop",
requireItems: true,
onClick: stop
}],
["aps/ToolbarButton", {
id: "srv_delete",
iconClass:"fa-trash",
type: "danger",
label: "Delete",
requireItems: true,
onClick: remove
}],
["aps/ToolbarButton", {
id: "srv_refresh",
iconClass:"fa-refresh",
label: "Refresh",
autoBusy: false,
onClick: refresh
}]
]]
]],
["aps/Tiles", {
title: "Resource consumption"
},[
["aps/Tile", {
title: "CPU power",
gridSize: "md-4"
}, [
["aps/UsageInfo", {
showPie: false,
value: at(self.usageModel.cpu, "usage"),
maximum: at(self.usageModel.cpu, "limit"),
textFirstNumber: '${value}',
description: 'core-hours',
hint: 'Limit: ${maximum}'
}]]],
["aps/Tile", {
title: "Memory usage",
gridSize: "md-4"
}, [
["aps/UsageInfo", {
showPie: false,
value: at(self.usageModel.ram, "usage"),
maximum: at(self.usageModel.ram, "limit"),
textFirstNumber: '${value}',
description: 'MB-hours',
hint: 'Limit: ${maximum}'
}]]],
["aps/Tile", {
title: "Disk usage",
gridSize: "md-4"
}, [
["aps/UsageInfo", {
textSuffix: "GB",
value: at(self.usageModel.disk, "usage"),
maximum: at(self.usageModel.disk, "limit"),
textFirstNumber: '${value}',
textSecondNumber: '${maximum}'
}]]]
]]
];
In the onContext
method, assign the proper values to the global variables and the data model, and then refresh the grid.
onContext: function(context) {
grid = this.byId("srv_grid");
page = this.byId("apsPageContainer");
var mgmtContext = context.vars.context;
contextId = mgmtContext.aps.id;
self.usageModel.set("cpu", mgmtContext.cpuUsageTotal);
self.usageModel.set("ram", mgmtContext.memoryUsageTotal);
self.usageModel.set("disk", mgmtContext.diskUsageTotal);
grid.refresh();
aps.apsc.hideLoading();
},
Define the onHide
method. The only button that calls another view is New. Thus, clear its state
by calling the cancel
function. Otherwise, it would show the loading state when a user comes back to this view.
onHide: function() {
this.byId("srv_new").cancel();
}
This completes the development of the ui/servers.js
script. You can compare it with
the similar file in the sample package
.