Skip to content

Commit

Permalink
F #2410: Integrate vm autorefresh in sunstone-server (#201)
Browse files Browse the repository at this point in the history
* Websocket autorefresh
* Integrate autorefresh in sunstone-server

Signed-off-by: Frederick Borges <[email protected]>
  • Loading branch information
Frederick Borges authored and rsmontero committed Sep 14, 2020
1 parent ede2864 commit 08343dd
Show file tree
Hide file tree
Showing 11 changed files with 214 additions and 10 deletions.
4 changes: 3 additions & 1 deletion install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,8 @@ VAR_DIRS="$VAR_LOCATION/remotes \
SUNSTONE_DIRS="$SUNSTONE_LOCATION/routes \
$SUNSTONE_LOCATION/models \
$SUNSTONE_LOCATION/models/OpenNebulaJSON \
$SUNSTONE_LOCATION/views"
$SUNSTONE_LOCATION/views \
$SUNSTONE_LOCATION/services"

SUNSTONE_MINIFIED_DIRS="$SUNSTONE_LOCATION/public \
$SUNSTONE_LOCATION/public/dist \
Expand Down Expand Up @@ -735,6 +736,7 @@ INSTALL_SUNSTONE_FILES=(
SUNSTONE_MODELS_JSON_FILES:$SUNSTONE_LOCATION/models/OpenNebulaJSON
SUNSTONE_VIEWS_FILES:$SUNSTONE_LOCATION/views
SUNSTONE_ROUTES_FILES:$SUNSTONE_LOCATION/routes
SUNSTONE_SERVICES_FILES:$SUNSTONE_LOCATION/services
)

INSTALL_SUNSTONE_PUBLIC_MINIFIED_FILES=(
Expand Down
1 change: 1 addition & 0 deletions share/install_gems/Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ group :sunstone do
gem 'memcache-client'
gem 'dalli'
gem 'rotp'
gem 'sinatra-websocket'
end

group :oca do
Expand Down
9 changes: 8 additions & 1 deletion src/sunstone/etc/sunstone-server.conf
Original file line number Diff line number Diff line change
Expand Up @@ -257,4 +257,11 @@
# This change the thresholds of dashboard resource usage
:threshold_min: 0
:threshold_low: 33
:threshold_high: 66
:threshold_high: 66

################################################################################
# Autorefresh websocket configuration
################################################################################

:zeromq_server: tcp://localhost:2101
:autorefresh_ip: 127.0.0.1
3 changes: 3 additions & 0 deletions src/sunstone/public/app/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ define(function(require) {
var Menu = require('utils/menu');
var Locale = require('utils/locale');
var UserAndZoneTemplate = require('hbs!sunstone/user_and_zone');
var Websocket = require("utils/websocket");

var _commonDialogs = [
require('utils/dialogs/confirm'),
Expand Down Expand Up @@ -73,6 +74,8 @@ define(function(require) {
Sunstone.showTab(PROVISION_TAB_ID);
}

Websocket.start();

$('#loading').hide();
});

Expand Down
3 changes: 3 additions & 0 deletions src/sunstone/public/app/sunstone-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,9 @@ define(function(require) {
},
"isExtendedVmInfo": _config["system_config"] && _config["system_config"]["get_extended_vm_info"] && _config["system_config"]["get_extended_vm_info"] === "true",
"isLogEnabled": _config["zone_id"] === _config["id_own_federation"] ? true : false,
"autorefreshWSS": _config["system_config"]["autorefresh_wss"],
"autorefreshIP": _config["system_config"]["autorefresh_ip"],
"autorefreshPort": _config["system_config"]["autorefresh_port"],
};

return Config;
Expand Down
16 changes: 12 additions & 4 deletions src/sunstone/public/app/sunstone.js
Original file line number Diff line number Diff line change
Expand Up @@ -811,7 +811,7 @@ define(function(require) {
return context.data("element");
};

var _insertPanels = function(tabName, info, contextTabId, context) {
var _insertPanels = function(tabName, info, contextTabId, context, autorefresh=false) {
var context = context || $(".sunstone-info", $("#" + tabName));

context.data("element", info[Object.keys(info)[0]]);
Expand Down Expand Up @@ -885,10 +885,12 @@ define(function(require) {

context.html(html);
$.each(SunstoneCfg["tabs"][tabName]["panelInstances"], function(panelName, panel) {
panel.setup(context);
if (!autorefresh || panelName == "vm_info_tab"){
panel.setup(context);

if(isRefresh && prevPanelStates[panelName] && panel.setState){
panel.setState( prevPanelStates[panelName], context );
if(isRefresh && prevPanelStates[panelName] && panel.setState){
panel.setState( prevPanelStates[panelName], context );
}
}
});

Expand All @@ -914,6 +916,11 @@ define(function(require) {
}
};

var _autorefreshVM = function(tabName, info, contextTabId, context) {
_insertPanels(tabName, info, contextTabId, context, true);
};


//Runs a predefined action. Wraps the calls to opennebula.js and
//can be use to run action depending on conditions and notify them
//if desired. Returns 1 if some problem has been detected: i.e
Expand Down Expand Up @@ -1358,6 +1365,7 @@ define(function(require) {

"insertTabs": _insertTabs,
"insertPanels": _insertPanels,
"autorefreshVM": _autorefreshVM,
"getElementRightInfo": _getElementRightInfo,

"showTab": _showTab,
Expand Down
4 changes: 4 additions & 0 deletions src/sunstone/public/app/tabs/vms-tab/panels/info.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ define(function(require) {
var TemplateTableVcenter = require("utils/panel/template-table");
var OpenNebula = require("opennebula");
var Navigation = require("utils/navigation");
var Websocket = require("utils/websocket");

/*
TEMPLATES
Expand Down Expand Up @@ -169,5 +170,8 @@ define(function(require) {
}
TemplateTable.setup(strippedTemplate, RESOURCE, this.element.ID, context, unshownValues, strippedTemplateVcenter);
TemplateTableVcenter.setup(strippedTemplateVcenter, RESOURCE, this.element.ID, context, unshownValues, strippedTemplate);

Websocket.subscribe(this.element.ID);

}
});
4 changes: 2 additions & 2 deletions src/sunstone/public/app/tabs/vms-tab/panels/info/html.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@
{{{renameTrHTML}}}
<tr>
<td class="key_td">{{tr "State"}}</td>
<td class="value_td">{{stateStr}}</td>
<td id="state_value" class="value_td">{{stateStr}}</td>
<td></td>
</tr>
<tr>
<td class="key_td">{{tr "LCM State"}}</td>
<td class="value_td">{{lcmStateStr}}</td>
<td id="lcm_state_value" class="value_td">{{lcmStateStr}}</td>
<td></td>
</tr>
<tr>
Expand Down
112 changes: 112 additions & 0 deletions src/sunstone/public/app/utils/websocket.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2020, OpenNebula Project, OpenNebula Systems */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */

define(function (require) {

var Config = require("sunstone-config");
var Sunstone = require('sunstone');


// user config
const wss = Config.autorefreshWSS || 'ws';
const port = Config.autorefreshPort || 9869;
const host = Config.autorefreshIP || '127.0.0.1';

var address = wss + "://" + host + ":" + port + "/ws";
var ws = new WebSocket(address);

var _start = function () {
ws.addEventListener('open', function (event) {
console.log("Connected to websocket");
ws.readyState = 1;
// Send CSRF token
var msg = {
"STATE": ws.readyState,
"ACTION": "authenticate",
}

ws.send(JSON.stringify(msg));
});

// Listen for messages
ws.addEventListener('message', function (event) {
var vm_info = JSON.parse(event.data);
// console.log(vm_info);
var response = { "VM": vm_info.HOOK_MESSAGE.VM };
var request = {
"request": {
"data": [response.ID],
"method": "show",
"resource": "VM"
}
}

// update VM

var TAB_ID = "vms-tab";
var tab = $('#' + TAB_ID);
Sunstone.getDataTable(TAB_ID).updateElement(request, response);
if (Sunstone.rightInfoVisible(tab) && vm_info.HOOK_MESSAGE.RESOURCE_ID == Sunstone.rightInfoResourceId(tab)) {
Sunstone.autorefreshVM(TAB_ID, response);
}

if (vm_info.HOOK_MESSAGE.STATE == "DONE"){
Sunstone.getDataTable(TAB_ID).waitingNodes();
Sunstone.runAction("VM.list", {force: true});
}

});

// Close Socket when close browser or tab.
window.onbeforeunload = function () {
_close();
};
};

var _subscribe = function (vm_id, context) {
var msg = {
"SUBSCRIBE": true,
"VM": vm_id
}

ws.send(JSON.stringify(msg));
};

var _unsubscribe = function (vm_id) {
var msg = {
"SUBSCRIBE": false,
"VM": vm_id
}

ws.send(JSON.stringify(msg));
};

var _close = function () {
ws.onclose = function () { }; // disable onclose handler first
ws.close()
};



var websocket = {
"start": _start,
"subscribe": _subscribe,
"unsubscribe": _unsubscribe,
"close": _close
};

return websocket;
});
62 changes: 61 additions & 1 deletion src/sunstone/sunstone-server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,12 @@
require 'SunstoneServer'
require 'SunstoneViews'

require 'sinatra-websocket'
require 'eventmachine'
require 'json'
require 'active_support/core_ext/hash'
require 'ffi-rzmq'

begin
require "SunstoneWebAuthn"
webauthn_avail = true
Expand Down Expand Up @@ -161,6 +167,7 @@
set :config, $conf
set :bind, $conf[:host]
set :port, $conf[:port]
set :sockets, []

if (proxy = $conf[:proxy])
ENV['http_proxy'] = proxy
Expand Down Expand Up @@ -262,6 +269,35 @@
set :erb, :trim => '-'
end

#start Autorefresh server

## 0MQ variables
@context = ZMQ::Context.new(1)
@subscriber = @context.socket(ZMQ::SUB)

## Subscribe to VM changes
@subscriber.setsockopt(ZMQ::SUBSCRIBE, "EVENT VM")
@subscriber.connect($conf[:zeromq_server])

# Create a thread to get ZeroMQ messages
Thread.new do
loop do
key = ''
content = ''

@subscriber.recv_string(key)
@subscriber.recv_string(content)

message = Hash.from_xml(Base64.decode64(content)).to_json

if (key != '')
settings.sockets.each do |client|
client.send(message)
end
end
end
end

$addons = OpenNebulaAddons.new(logger)

DEFAULT_TABLE_ORDER = "desc"
Expand Down Expand Up @@ -461,6 +497,9 @@ def build_session
session[:default_view] = $views_config.available_views(session[:user], session[:user_gname]).first
end

autorefresh_wss = $conf[:autorefresh_support_wss]
session[:autorefresh_wss] = autorefresh_wss == 'yes'? 'wss' : 'ws'

# end user options

# secure cookies
Expand Down Expand Up @@ -507,7 +546,7 @@ def destroy_session
@request_body = request.body.read
request.body.rewind

unless %w(/ /login /vnc /spice /version /webauthn_options_for_get).include?(request.path)
unless %w(/ /login /vnc /spice /version /webauthn_options_for_get /ws).include?(request.path)
halt [401, "csrftoken"] unless authorized? && valid_csrftoken?
end

Expand Down Expand Up @@ -626,6 +665,27 @@ def destroy_session
}
end

get '/ws' do
logger.info { 'Incomming WS connection' }
if request.websocket?
request.websocket do |ws|
ws.onopen do
logger.info { "New client registered" }
settings.sockets << ws
end

ws.onmessage do |msg|
logger.info { "New message received: #{msg}" }
end

ws.onclose do
logger.info { "Client disconnected." }
settings.sockets.delete(ws)
end
end
end
end

get '/login' do
content_type 'text/html', :charset => 'utf-8'
if !authorized?
Expand Down
6 changes: 5 additions & 1 deletion src/sunstone/views/index.erb
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,11 @@
'max_upload_file_size' : <%= $conf[:max_upload_file_size] ? $conf[:max_upload_file_size] : "undefined" %>,
'leases' : <%= $conf[:leases] ? $conf[:leases].to_json : "null" %>,
'mapped_ips' : '<%= $conf[:mapped_ips] ? $conf[:mapped_ips] : false %>',
'get_extended_vm_info': '<%= $conf[:get_extended_vm_info] ? $conf[:get_extended_vm_info] : false %>'
'get_extended_vm_info': '<%= $conf[:get_extended_vm_info] ? $conf[:get_extended_vm_info] : false %>',
'autorefresh_wss': '<%= session[:autorefresh_wss] %>',
'autorefresh_ip': '<%= $conf[:autorefresh_ip] %>',
'autorefresh_port': '<%= $conf[:port] %>',

},
'view' : view,
'available_views' : available_views,
Expand Down

0 comments on commit 08343dd

Please sign in to comment.