mirror of
https://github.com/OpenNebula/one.git
synced 2025-02-10 13:57:22 +03:00
Signed-off-by: Frederick Borges <fborges@opennebula.io>
This commit is contained in:
parent
84debc2545
commit
40ad20451a
11
install.sh
11
install.sh
@ -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 \
|
||||
@ -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=(
|
||||
@ -769,6 +771,7 @@ INSTALL_SUNSTONE_PUBLIC_MINIFIED_FILES=(
|
||||
INSTALL_SUNSTONE_PUBLIC_DEV_DIR=(
|
||||
SUNSTONE_PUBLIC_DEV_DIR:$SUNSTONE_LOCATION
|
||||
SUNSTONE_GUAC_DEV_DIR:$SUNSTONE_LOCATION
|
||||
SUNSTONE_AUTOREFRESH_DEV_DIR:$SUNSTONE_LOCATION/services/autorefresh
|
||||
)
|
||||
|
||||
INSTALL_SUNSTONE_ETC_FILES=(
|
||||
@ -898,6 +901,7 @@ RUBY_LIB_FILES="src/mad/ruby/ActionManager.rb \
|
||||
src/oca/ruby/opennebula.rb \
|
||||
src/sunstone/OpenNebulaVNC.rb \
|
||||
src/sunstone/OpenNebulaGuac.rb \
|
||||
src/sunstone/OpenNebulaAutorefresh.rb \
|
||||
src/sunstone/OpenNebulaAddons.rb \
|
||||
src/vmm_mad/remotes/vcenter/vcenter_driver.rb \
|
||||
src/vmm_mad/remotes/nsx/nsx_driver.rb \
|
||||
@ -2377,7 +2381,8 @@ SUNSTONE_FILES="src/sunstone/sunstone-server.rb \
|
||||
|
||||
SUNSTONE_BIN_FILES="src/sunstone/bin/sunstone-server \
|
||||
src/sunstone/bin/guac-server \
|
||||
src/sunstone/bin/novnc-server"
|
||||
src/sunstone/bin/novnc-server\
|
||||
src/sunstone/bin/autorefresh-server"
|
||||
|
||||
SUNSTONE_ETC_FILES="src/sunstone/etc/sunstone-server.conf \
|
||||
src/sunstone/etc/sunstone-views.yaml \
|
||||
@ -2451,6 +2456,8 @@ SUNSTONE_PUBLIC_JS_CONSOLE_FILES="src/sunstone/public/dist/console/vnc.js \
|
||||
|
||||
SUNSTONE_PUBLIC_DEV_DIR="src/sunstone/public"
|
||||
|
||||
SUNSTONE_AUTOREFRESH_DEV_DIR="src/sunstone/services/autorefresh"
|
||||
|
||||
SUNSTONE_ROUTES_FILES="src/sunstone/routes/oneflow.rb \
|
||||
src/sunstone/routes/vcenter.rb \
|
||||
src/sunstone/routes/support.rb \
|
||||
|
209
src/sunstone/OpenNebulaAutorefresh.rb
Normal file
209
src/sunstone/OpenNebulaAutorefresh.rb
Normal file
@ -0,0 +1,209 @@
|
||||
# -------------------------------------------------------------------------- #
|
||||
# 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. #
|
||||
#--------------------------------------------------------------------------- #
|
||||
|
||||
require 'opennebula'
|
||||
|
||||
##############################################################################
|
||||
# Global Variables
|
||||
##############################################################################
|
||||
|
||||
if !ONE_LOCATION
|
||||
AUTOREFRESH_LOCK_FILE = "/var/lock/one/.autorefresh.lock"
|
||||
else
|
||||
AUTOREFRESH_LOCK_FILE = ONE_LOCATION + "/var/.autorefresh.lock"
|
||||
end
|
||||
|
||||
KEEPALIVE_TIME = 15
|
||||
|
||||
LIB_LOCATION="/usr/lib/one"
|
||||
SUNSTONE_SERVICES_LOCATION=LIB_LOCATION+"/sunstone/services"
|
||||
|
||||
##############################################################################
|
||||
# Server
|
||||
##############################################################################
|
||||
|
||||
class OpenNebulaAutorefresh
|
||||
def initialize(config, logger)
|
||||
# Basics
|
||||
@logger = logger
|
||||
|
||||
# Autorefresh
|
||||
@lock_file = AUTOREFRESH_LOCK_FILE
|
||||
@server_ip = config[:autorefresh_ip]
|
||||
@server_port = config[:autorefresh_port]
|
||||
end
|
||||
|
||||
def start
|
||||
# Launch error if Autorefresh server is running
|
||||
if is_autorefresh_running?
|
||||
message="Autorefresh server already running"
|
||||
STDERR.puts message
|
||||
@logger.info message
|
||||
return false
|
||||
end
|
||||
|
||||
config_dir = SUNSTONE_SERVICES_LOCATION + "/autorefresh"
|
||||
config_file = config_dir + "/config.ru"
|
||||
|
||||
# Start Autorefresh server
|
||||
cmd = "thin start -R #{config_file} -p #{@server_port} -a #{@server_ip}";
|
||||
|
||||
begin
|
||||
@logger.info { "Starting Autorefresh server: #{cmd}" }
|
||||
pid=start_daemon(cmd, AUTOREFRESH_LOG)
|
||||
rescue Exception => e
|
||||
@logger.error e.message
|
||||
return false
|
||||
end
|
||||
|
||||
begin
|
||||
File.open(@lock_file, "w") do |f|
|
||||
f.write(pid.to_s)
|
||||
end
|
||||
rescue Exception => e
|
||||
@logger.error e.message
|
||||
Process.kill('-KILL', pid)
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
# Verify if Autorefresh server is running
|
||||
sleep 1
|
||||
|
||||
if !is_autorefresh_running?
|
||||
message="Error starting Autorefresh server"
|
||||
STDERR.puts message
|
||||
@logger.error message
|
||||
File.delete(@lock_file) if File.exist?(@lock_file)
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
STDOUT.puts "Autorefresh server started"
|
||||
|
||||
true
|
||||
|
||||
end
|
||||
|
||||
def stop(force=false)
|
||||
pid=get_autorefresh_pid
|
||||
|
||||
if pid
|
||||
@logger.info "Killing Autorefresh server"
|
||||
|
||||
signal=(force ? '-KILL' : '-TERM')
|
||||
Process.kill(signal ,pid)
|
||||
|
||||
sleep 1
|
||||
|
||||
begin
|
||||
Process.getpgid(pid)
|
||||
|
||||
Process.kill('-KILL', pid)
|
||||
rescue
|
||||
end
|
||||
|
||||
if is_autorefresh_running?
|
||||
message="Autorefresh server is still running"
|
||||
STDERR.puts message
|
||||
logger.error message
|
||||
return false
|
||||
end
|
||||
|
||||
else
|
||||
message="Autorefresh server is not running"
|
||||
@logger.info message
|
||||
STDERR.puts message
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
def status
|
||||
if is_autorefresh_running?
|
||||
STDOUT.puts "Autorefresh server is running"
|
||||
true
|
||||
else
|
||||
STDOUT.puts "Autorefresh server is NOT running"
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def is_autorefresh_running?
|
||||
if File.exist?(@lock_file)
|
||||
pid=File.read(@lock_file).strip
|
||||
|
||||
if system("ps #{pid} 1> /dev/null")
|
||||
return pid.to_i
|
||||
end
|
||||
|
||||
@logger.info "Deleting stale lock file"
|
||||
File.delete(@lock_file)
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
alias_method :get_autorefresh_pid, :is_autorefresh_running?
|
||||
|
||||
def is_lockfile?
|
||||
dn = File.dirname(@lock_file)
|
||||
bn = File.basename(@lock_file)
|
||||
|
||||
# Due to restrictions which doesn't allow to stat the lock file
|
||||
# when Sunstone is running under Apache with SELinux enabled,
|
||||
# as a workaround we read content of the whole lock directory.
|
||||
begin
|
||||
Dir.entries(dn).include?(bn)
|
||||
rescue StandardError
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
if RUBY_VERSION<'1.9'
|
||||
def spawn(*args)
|
||||
fork {
|
||||
command=args[0..-2]
|
||||
|
||||
# Close stdin and point out and err to log file
|
||||
$stdout.reopen(AUTOREFRESH_LOG, "a")
|
||||
$stderr.reopen(AUTOREFRESH_LOG, "a")
|
||||
$stdin.close
|
||||
|
||||
# Detach process from the parent
|
||||
Process.setsid
|
||||
|
||||
exec(*command)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def start_daemon(cmd, log)
|
||||
options={
|
||||
:pgroup => true,
|
||||
:in => :close,
|
||||
[:out, :err] => [log, "a"],
|
||||
:close_others => true }
|
||||
|
||||
params=cmd.split(" ")+[options]
|
||||
pid=spawn( *params )
|
||||
|
||||
Process.detach(pid)
|
||||
|
||||
pid
|
||||
end
|
||||
end
|
90
src/sunstone/bin/autorefresh-server
Executable file
90
src/sunstone/bin/autorefresh-server
Executable file
@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env ruby
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# -------------------------------------------------------------------------- #
|
||||
# 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. #
|
||||
#--------------------------------------------------------------------------- #
|
||||
|
||||
ONE_LOCATION = ENV['ONE_LOCATION']
|
||||
|
||||
if !ONE_LOCATION
|
||||
LOG_LOCATION = '/var/log/one'
|
||||
VAR_LOCATION = '/var/lib/one'
|
||||
SHARE_LOCATION = '/usr/share/one'
|
||||
ETC_LOCATION = '/etc/one'
|
||||
RUBY_LIB_LOCATION = '/usr/lib/one/ruby'
|
||||
GEMS_LOCATION = '/usr/share/one/gems'
|
||||
else
|
||||
VAR_LOCATION = ONE_LOCATION + '/var'
|
||||
LOG_LOCATION = ONE_LOCATION + '/var'
|
||||
SHARE_LOCATION = ONE_LOCATION + '/share'
|
||||
ETC_LOCATION = ONE_LOCATION + '/etc'
|
||||
RUBY_LIB_LOCATION = ONE_LOCATION + '/lib/ruby'
|
||||
GEMS_LOCATION = ONE_LOCATION + '/share/gems'
|
||||
end
|
||||
|
||||
AUTOREFRESH_LOG = LOG_LOCATION + "/autorefresh.log"
|
||||
CONFIGURATION_FILE = ETC_LOCATION + "/sunstone-server.conf"
|
||||
PLUGIN_CONFIGURATION_FILE = ETC_LOCATION + "/sunstone-plugins.yaml"
|
||||
SUNSTONE_ROOT_DIR = File.dirname(__FILE__)
|
||||
|
||||
if File.directory?(GEMS_LOCATION)
|
||||
$LOAD_PATH.reject! {|l| l =~ /vendor_ruby/ }
|
||||
require 'rubygems'
|
||||
Gem.use_paths(File.realpath(GEMS_LOCATION))
|
||||
end
|
||||
|
||||
$LOAD_PATH << RUBY_LIB_LOCATION
|
||||
$LOAD_PATH << RUBY_LIB_LOCATION + '/cloud'
|
||||
$LOAD_PATH << SUNSTONE_ROOT_DIR
|
||||
$LOAD_PATH << SUNSTONE_ROOT_DIR + '/models'
|
||||
|
||||
require 'logger'
|
||||
require 'yaml'
|
||||
require 'OpenNebulaAutorefresh'
|
||||
|
||||
$log=Logger.new(AUTOREFRESH_LOG)
|
||||
|
||||
|
||||
begin
|
||||
conf = YAML.load_file(CONFIGURATION_FILE)
|
||||
rescue Exception => e
|
||||
STDERR.puts "Error parsing config file #{CONFIGURATION_FILE}: #{e.message}"
|
||||
exit 1
|
||||
end
|
||||
|
||||
autorefresh=OpenNebulaAutorefresh.new(conf, $log)
|
||||
|
||||
if ARGV[0]
|
||||
res=case ARGV[0].downcase.to_sym
|
||||
when :start
|
||||
autorefresh.start
|
||||
when :stop
|
||||
autorefresh.stop(true)
|
||||
when :restart
|
||||
autorefresh.stop(true)
|
||||
sleep 1
|
||||
autorefresh.start
|
||||
when :status
|
||||
autorefresh.status
|
||||
end
|
||||
|
||||
if !res
|
||||
STDERR.puts "Error, check #{AUTOREFRESH_LOG}"
|
||||
exit(-1)
|
||||
end
|
||||
else
|
||||
exit(-1)
|
||||
end
|
@ -26,6 +26,7 @@ if [ -z "$ONE_LOCATION" ]; then
|
||||
SUNSTONE_CONF=/etc/one/sunstone-server.conf
|
||||
NOVNC_SERVER=/usr/bin/novnc-server
|
||||
GUACAMOLE_SERVER=/usr/bin/guac-server
|
||||
AUTOREFRESH_SERVER=/usr/bin/autorefresh-server
|
||||
else
|
||||
SUNSTONE_PID=$ONE_LOCATION/var/sunstone.pid
|
||||
SUNSTONE_SERVER=$ONE_LOCATION/lib/sunstone/sunstone-server.rb
|
||||
@ -35,6 +36,7 @@ else
|
||||
SUNSTONE_CONF=$ONE_LOCATION/etc/sunstone-server.conf
|
||||
NOVNC_SERVER=$ONE_LOCATION/bin/novnc-server
|
||||
GUACAMOLE_SERVER=$ONE_LOCATION/bin/guac-server
|
||||
AUTOREFRESH_SERVER=$ONE_LOCATION/bin/autorefresh-server
|
||||
fi
|
||||
|
||||
setup()
|
||||
@ -63,10 +65,11 @@ setup()
|
||||
|
||||
start()
|
||||
{
|
||||
while getopts "ng" opt; do
|
||||
while getopts "ngr" opt; do
|
||||
case "${opt}" in
|
||||
n) novnc=1 ;;
|
||||
g) guacamole=1 ;;
|
||||
r) autorefresh=1 ;;
|
||||
*) echo "Invalid option: $OPTARG" 1>&2 ;;
|
||||
esac
|
||||
done
|
||||
@ -94,6 +97,15 @@ start()
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$autorefresh" = "1" ]; then
|
||||
# Start Autorefresh server
|
||||
$AUTOREFRESH_SERVER start
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
echo "Could not start Autorefresh server" 1>&2
|
||||
fi
|
||||
fi
|
||||
|
||||
# Start the sunstone daemon
|
||||
touch $SUNSTONE_LOCK_FILE
|
||||
|
||||
@ -102,6 +114,7 @@ start()
|
||||
|
||||
$NOVNC_SERVER stop
|
||||
$GUACAMOLE_SERVER stop
|
||||
$AUTOREFRESH_SERVER stop
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@ -113,6 +126,7 @@ start()
|
||||
echo "Check $SUNSTONE_LOG_ERROR and $SUNSTONE_LOG for more information"
|
||||
[ "$novnc" = "1" ] && $NOVNC_SERVER stop
|
||||
[ "$guacamole" = "1" ] && $GUACAMOLE_SERVER stop
|
||||
[ "$autorefresh" = "1" ] && $AUTOREFRESH_SERVER stop
|
||||
exit 1
|
||||
else
|
||||
echo $LASTPID > $SUNSTONE_PID
|
||||
@ -126,6 +140,7 @@ start()
|
||||
echo "Check $SUNSTONE_LOG_ERROR and $SUNSTONE_LOG for more information"
|
||||
[ "$novnc" = "1" ] && $NOVNC_SERVER stop
|
||||
[ "$guacamole" = "1" ] && $GUACAMOLE_SERVER stop
|
||||
[ "$autorefresh" = "1" ] && $AUTOREFRESH_SERVER stop
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@ -137,10 +152,11 @@ start()
|
||||
#
|
||||
stop()
|
||||
{
|
||||
while getopts "ng" opt; do
|
||||
while getopts "ngr" opt; do
|
||||
case "${opt}" in
|
||||
n) novnc=1 ;;
|
||||
g) guacamole=1 ;;
|
||||
r) autorefresh=1 ;;
|
||||
*) echo "Invalid option: $OPTARG" 1>&2 ;;
|
||||
esac
|
||||
done
|
||||
@ -151,6 +167,9 @@ stop()
|
||||
# Stop guacamole server
|
||||
[ "$guacamole" = "1" ] && $GUACAMOLE_SERVER stop
|
||||
|
||||
# Stop autorefresh server
|
||||
[ "$autorefresh" = "1" ] && $AUTOREFRESH_SERVER stop
|
||||
|
||||
if [ ! -f $SUNSTONE_PID ]; then
|
||||
echo "Couldn't find sunstone-server process pid." >&2
|
||||
return 1
|
||||
@ -170,16 +189,16 @@ stop()
|
||||
case "$1" in
|
||||
start)
|
||||
setup
|
||||
start -ng
|
||||
start -ngr
|
||||
;;
|
||||
stop)
|
||||
stop -ng
|
||||
stop -ngr
|
||||
exit $?
|
||||
;;
|
||||
restart)
|
||||
stop -ng 2> /dev/null
|
||||
stop -ngr 2> /dev/null
|
||||
setup
|
||||
start -ng
|
||||
start -ngr
|
||||
;;
|
||||
start-sunstone)
|
||||
setup
|
||||
@ -189,7 +208,7 @@ case "$1" in
|
||||
stop
|
||||
;;
|
||||
restart-sunstone)
|
||||
stop -ng 2> /dev/null
|
||||
stop -ngr 2> /dev/null
|
||||
setup
|
||||
start
|
||||
;;
|
||||
|
@ -257,4 +257,12 @@
|
||||
# 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
|
||||
:autorefresh_port: 2346
|
@ -21,6 +21,7 @@ include OpenNebulaJSON
|
||||
|
||||
require 'OpenNebulaVNC'
|
||||
require 'OpenNebulaGuac'
|
||||
require 'OpenNebulaAutorefresh'
|
||||
require 'OpenNebulaAddons'
|
||||
require 'OpenNebulaJSON/JSONUtils'
|
||||
#include JSONUtils
|
||||
|
@ -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'),
|
||||
@ -73,6 +74,8 @@ define(function(require) {
|
||||
Sunstone.showTab(PROVISION_TAB_ID);
|
||||
}
|
||||
|
||||
Websocket.start();
|
||||
|
||||
$('#loading').hide();
|
||||
});
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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]]);
|
||||
@ -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 );
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -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
|
||||
@ -1358,6 +1365,7 @@ define(function(require) {
|
||||
|
||||
"insertTabs": _insertTabs,
|
||||
"insertPanels": _insertPanels,
|
||||
"autorefreshVM": _autorefreshVM,
|
||||
"getElementRightInfo": _getElementRightInfo,
|
||||
|
||||
"showTab": _showTab,
|
||||
|
@ -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
|
||||
@ -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);
|
||||
|
||||
}
|
||||
});
|
||||
|
@ -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>
|
||||
|
116
src/sunstone/public/app/utils/websocket.js
Normal file
116
src/sunstone/public/app/utils/websocket.js
Normal file
@ -0,0 +1,116 @@
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* 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 || 2346;
|
||||
const host = Config.autorefreshIP || '127.0.0.1';
|
||||
|
||||
var address = wss + "://" + host + ":" + port;
|
||||
var ws = new WebSocket(address);
|
||||
var csrftoken;
|
||||
|
||||
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",
|
||||
"DATA": {
|
||||
"csrf-token": csrftoken,
|
||||
},
|
||||
}
|
||||
|
||||
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;
|
||||
});
|
123
src/sunstone/services/autorefresh/autorefresh-server.rb
Normal file
123
src/sunstone/services/autorefresh/autorefresh-server.rb
Normal file
@ -0,0 +1,123 @@
|
||||
# -------------------------------------------------------------------------- #
|
||||
# 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. #
|
||||
#--------------------------------------------------------------------------- #
|
||||
|
||||
require 'faye/websocket'
|
||||
require 'eventmachine'
|
||||
require 'json'
|
||||
require 'active_support/core_ext/hash'
|
||||
require 'ffi-rzmq'
|
||||
require 'base64'
|
||||
|
||||
##############################################################################
|
||||
# Global Variables
|
||||
##############################################################################
|
||||
|
||||
@context = ZMQ::Context.new(1)
|
||||
@subscriber = @context.socket(ZMQ::SUB)
|
||||
@clients = []
|
||||
@zeromq_server = ""
|
||||
|
||||
KEEPALIVE_TIME = 15
|
||||
CONFIGURATION_FILE = ETC_LOCATION + '/sunstone-server.conf'
|
||||
|
||||
##############################################################################
|
||||
# Methods
|
||||
##############################################################################
|
||||
|
||||
# Reads the configuration file and creates the zeromq server ip
|
||||
def get_zeroMQ_server_ip()
|
||||
begin
|
||||
$conf = YAML.load_file(CONFIGURATION_FILE)
|
||||
rescue Exception => e
|
||||
STDERR.puts "Error parsing config file #{CONFIGURATION_FILE}: #{e.message}"
|
||||
exit 1
|
||||
end
|
||||
|
||||
puts $conf[:zeromq_server]
|
||||
@zeromq_server = $conf[:zeromq_server]
|
||||
end
|
||||
|
||||
# Configures the ZeroMQ connection to recieve `event` notifications
|
||||
def configure_zeroMQ(event="VM")
|
||||
@subscriber.setsockopt(ZMQ::SUBSCRIBE, "EVENT #{event}")
|
||||
@subscriber.connect(@zeromq_server)
|
||||
puts "Subscribed to #{event}"
|
||||
end
|
||||
|
||||
# Broadcast event to all clients
|
||||
def broadcast_message(message)
|
||||
@clients.each do |client|
|
||||
client.send(message)
|
||||
end
|
||||
end
|
||||
|
||||
# Gets the ZeroMQ incomming messages and broadcast
|
||||
# them to all clients connected
|
||||
def get_zeroMQ_messages()
|
||||
key = ''
|
||||
content = ''
|
||||
|
||||
@subscriber.recv_string(key)
|
||||
@subscriber.recv_string(content)
|
||||
|
||||
mensaje = Hash.from_xml(Base64.decode64(content)).to_json
|
||||
|
||||
puts "key: #{key}"
|
||||
|
||||
if (key != '')
|
||||
broadcast_message(mensaje)
|
||||
end
|
||||
end
|
||||
|
||||
##############################################################################
|
||||
# Server
|
||||
##############################################################################
|
||||
|
||||
get_zeroMQ_server_ip()
|
||||
configure_zeroMQ()
|
||||
|
||||
# Create a thread to get ZeroMQ messages
|
||||
Thread.new do
|
||||
loop do
|
||||
get_zeroMQ_messages()
|
||||
end
|
||||
end
|
||||
|
||||
Autorefresh = lambda do |env|
|
||||
if Faye::WebSocket.websocket?(env)
|
||||
ws = Faye::WebSocket.new(env, nil, {ping: KEEPALIVE_TIME })
|
||||
|
||||
ws.on :open do |event|
|
||||
puts "New client registered: #{ws.object_id}"
|
||||
@clients << ws
|
||||
end
|
||||
|
||||
ws.on :message do |event|
|
||||
puts "New message received: #{event.data}"
|
||||
end
|
||||
|
||||
ws.on :close do |event|
|
||||
puts "Client #{ws.object_id} disconnected. Reason: #{event.reason}"
|
||||
@clients.delete(ws)
|
||||
end
|
||||
|
||||
# Return async Rack response
|
||||
ws.rack_response
|
||||
else
|
||||
# Normal HTTP request
|
||||
[401, { 'Content-Type' => 'text/plain' }, ['Unauthorized']]
|
||||
end
|
||||
end
|
35
src/sunstone/services/autorefresh/config.ru
Normal file
35
src/sunstone/services/autorefresh/config.ru
Normal file
@ -0,0 +1,35 @@
|
||||
# -------------------------------------------------------------------------- #
|
||||
# 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. #
|
||||
#--------------------------------------------------------------------------- #
|
||||
|
||||
$: << '.'
|
||||
|
||||
ONE_LOCATION = ENV['ONE_LOCATION']
|
||||
|
||||
if !ONE_LOCATION
|
||||
ETC_LOCATION = '/etc/one'
|
||||
SUNSTONE_LOCATION = '/usr/lib/one/sunstone'
|
||||
else
|
||||
ETC_LOCATION = ONE_LOCATION + '/etc'
|
||||
SUNSTONE_LOCATION = ONE_LOCATION + '/lib/sunstone'
|
||||
end
|
||||
|
||||
SUNSTONE_SERVICES = SUNSTONE_LOCATION + '/services'
|
||||
|
||||
require SUNSTONE_SERVICES + '/autorefresh/autorefresh-server'
|
||||
|
||||
Faye::WebSocket.load_adapter('thin')
|
||||
|
||||
run Autorefresh
|
@ -262,6 +262,16 @@ configure do
|
||||
set :erb, :trim => '-'
|
||||
end
|
||||
|
||||
#start Autorefresh server
|
||||
|
||||
$autorefresh = OpenNebulaAutorefresh.new($conf, logger)
|
||||
|
||||
configure do
|
||||
set :run, false
|
||||
set :autorefresh, $autorefresh
|
||||
set :erb, :trim => '-'
|
||||
end
|
||||
|
||||
$addons = OpenNebulaAddons.new(logger)
|
||||
|
||||
DEFAULT_TABLE_ORDER = "desc"
|
||||
@ -462,6 +472,9 @@ helpers do
|
||||
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
|
||||
|
@ -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[:autorefresh_port] %>',
|
||||
|
||||
},
|
||||
'view' : view,
|
||||
'available_views' : available_views,
|
||||
|
Loading…
x
Reference in New Issue
Block a user