1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-16 22:50:10 +03:00

F #4994: Add extra info to remote connection (#764)

This commit is contained in:
Sergio Betanzos 2021-02-08 10:40:30 +01:00 committed by GitHub
parent 89379d9ffb
commit 0b5453a234
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 632 additions and 279 deletions

View File

@ -951,9 +951,6 @@ RUBY_LIB_FILES="src/mad/ruby/ActionManager.rb \
src/mad/ruby/ssh_stream.rb \
src/vnm_mad/one_vnm.rb \
src/oca/ruby/opennebula.rb \
src/sunstone/OpenNebulaVNC.rb \
src/sunstone/opennebula_guac.rb \
src/sunstone/opennebula_vmrc.rb \
src/sunstone/OpenNebulaAddons.rb \
src/vmm_mad/remotes/vcenter/vcenter_driver.rb \
src/vmm_mad/remotes/nsx/nsx_driver.rb \
@ -2477,12 +2474,16 @@ SUNSTONE_ETC_VIEW_MIXED="src/sunstone/etc/sunstone-views/mixed/admin.yaml \
src/sunstone/etc/sunstone-views/mixed/groupadmin.yaml"
SUNSTONE_MODELS_FILES="src/sunstone/models/OpenNebulaJSON.rb \
src/sunstone/models/SunstoneServer.rb \
src/sunstone/models/SunstoneViews.rb \
src/sunstone/models/OpenNebula2FA/SunstoneWebAuthn.rb \
src/sunstone/models/OpenNebula2FA/sunstone_qr_code.rb \
src/sunstone/models/OpenNebula2FA/sunstone_optp.rb \
src/sunstone/models/OpenNebula2FA/sunstone_2f_auth.rb"
src/sunstone/models/SunstoneServer.rb \
src/sunstone/models/SunstoneViews.rb \
src/sunstone/models/sunstone_vm_helper.rb \
src/sunstone/models/sunstone_vnc.rb \
src/sunstone/models/sunstone_guac.rb \
src/sunstone/models/sunstone_vmrc.rb \
src/sunstone/models/OpenNebula2FA/SunstoneWebAuthn.rb \
src/sunstone/models/OpenNebula2FA/sunstone_qr_code.rb \
src/sunstone/models/OpenNebula2FA/sunstone_optp.rb \
src/sunstone/models/OpenNebula2FA/sunstone_2f_auth.rb"
SUNSTONE_MODELS_JSON_FILES="src/sunstone/models/OpenNebulaJSON/HostJSON.rb \
src/sunstone/models/OpenNebulaJSON/ImageJSON.rb \

View File

@ -240,7 +240,10 @@ AllCops:
- src/sunstone/test/spec/host_spec.rb
- src/sunstone/test/spec/user_spec.rb
- src/sunstone/OpenNebulaAddons.rb
- src/sunstone/OpenNebulaVNC.rb
- src/sunstone/models/sunstone_vnc.rb
- src/sunstone/models/sunstone_guac.rb
- src/sunstone/models/sunstone_vmrc.rb
- src/sunstone/models/sunstone_vm_helper.rb
- src/sunstone/models/OpenNebulaJSON.rb
- src/sunstone/models/SunstoneViews.rb
- src/sunstone/models/SunstoneServer.rb

View File

@ -25,6 +25,7 @@ if !ONE_LOCATION
SHARE_LOCATION = '/usr/share/one'
ETC_LOCATION = '/etc/one'
RUBY_LIB_LOCATION = '/usr/lib/one/ruby'
SUNSTONE_ROOT_DIR = '/usr/lib/one/sunstone'
GEMS_LOCATION = '/usr/share/one/gems'
else
VAR_LOCATION = ONE_LOCATION + '/var'
@ -32,13 +33,13 @@ else
SHARE_LOCATION = ONE_LOCATION + '/share'
ETC_LOCATION = ONE_LOCATION + '/etc'
RUBY_LIB_LOCATION = ONE_LOCATION + '/lib/ruby'
SUNSTONE_ROOT_DIR = ONE_LOCATION + '/lib/sunstone'
GEMS_LOCATION = ONE_LOCATION + '/share/gems'
end
VNC_LOG = LOG_LOCATION + "/novnc.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/ }
@ -53,7 +54,7 @@ $LOAD_PATH << SUNSTONE_ROOT_DIR + '/models'
require 'logger'
require 'yaml'
require 'OpenNebulaVNC'
require 'sunstone_vnc'
$log=Logger.new(VNC_LOG)
@ -65,7 +66,7 @@ rescue Exception => e
exit 1
end
vnc=OpenNebulaVNC.new(conf, $log)
vnc=SunstoneVNC.new(conf, $log)
if ARGV[0]
res=case ARGV[0].downcase.to_sym

View File

@ -19,9 +19,10 @@ require 'CloudServer'
require 'OpenNebulaJSON'
include OpenNebulaJSON
require 'OpenNebulaVNC'
require 'opennebula_guac'
require 'opennebula_vmrc'
require 'sunstone_vnc'
require 'sunstone_guac'
require 'sunstone_vmrc'
require 'sunstone_vm_helper'
require 'OpenNebulaAddons'
require 'OpenNebulaJSON/JSONUtils'
#include JSONUtils

View File

@ -109,7 +109,7 @@ GUAC_STATES = [
]
# Class for Guacamole connection configuration
class OpenNebulaGuac
class SunstoneGuac
attr_reader :proxy_port
@ -159,6 +159,9 @@ class OpenNebulaGuac
return error(400, 'Fireedge_key is not available')
end
info = SunstoneVMHelper.get_remote_info(vm_resource)
encode_info = Base64.encode64(info.to_json)
data = encrypt_data(
{
'connection' => {
@ -174,7 +177,7 @@ class OpenNebulaGuac
}
)
[200, { :token => data }.to_json]
[200, { :token => data, :info => encode_info }.to_json]
end
private

View File

@ -0,0 +1,88 @@
# -------------------------------------------------------------------------- #
# 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. #
#--------------------------------------------------------------------------- #
module SunstoneVMHelper
class << self
def state_to_str(id, lcm_id)
id = id.to_i
state_str = VirtualMachine::VM_STATE[id]
if state_str == 'ACTIVE'
lcm_id = lcm_id.to_i
return VirtualMachine::LCM_STATE[lcm_id]
end
return state_str
end
def get_ips(vm)
ips = []
vm_nics = []
if !vm['TEMPLATE']['NIC'].nil?
vm_nics = [vm['TEMPLATE']['NIC']].flatten
end
if !vm['TEMPLATE']['PCI'].nil?
vm_nics = [vm_nics, vm['TEMPLATE']['PCI']].flatten
end
vm_nics.each do |nic|
%w[IP EXTERNAL_IP IP6_GLOBAL IP6_ULA IP6
VROUTER_IP VROUTER_IP6_GLOBAL VROUTER_IP6_ULA].each do |attr|
if nic.key?(attr)
ips.push(nic[attr])
end
end
end
VirtualMachine::EXTERNAL_IP_ATTRS.each do |attr|
external_ip = vm['MONITORING'][attr]
if !external_ip.nil? && !ips.include?(external_ip)
ips.push(external_ip)
end
end
return ips
end
def get_remote_info(vm_resource)
vm = vm_resource.to_hash['VM']
service_id = vm['USER_TEMPLATE']['SERVICE_ID']
info = {
:id => vm['ID'],
:name => vm['NAME'],
:state => state_to_str(vm['STATE'], vm['LCM_STATE']),
:start_time => vm['STIME'],
:networks => get_ips(vm)
}
info[:service_id] = service_id if service_id
return info
end
end
end

View File

@ -107,7 +107,7 @@ VMRC_STATES = [
]
# Class for necessary VMRC ticket creation
class OpenNebulaVMRC
class SunstoneVMRC
attr_reader :proxy_port

View File

@ -103,7 +103,7 @@ VNC_STATES = [
#68, #HOTPLUG_SAVEAS_STOPPED
]
class OpenNebulaVNC
class SunstoneVNC
attr_reader :proxy_port
@ -243,10 +243,13 @@ class OpenNebulaVNC
return error(500, "Cannot create VNC proxy token")
end
info = SunstoneVMHelper.get_remote_info(vm_resource)
encode_info = Base64.encode64(info.to_json)
info = {
:password => vnc_pw,
:token => random_str,
:vm_name => vm_resource['NAME']
:info => encode_info
}
return [200, info.to_json]

View File

@ -17,7 +17,8 @@
define(function(require) {
require('spice-main');
var host = null, port = null;
var UtilsConnection = require("utils/info-connection/utils");
var sc;
function spice_set_cookie(name, value, days) {
@ -41,10 +42,16 @@ define(function(require) {
}
function connect() {
var host, port, password, scheme = "ws://", uri;
var info = spice_query_var('info', undefined);
var info_decode = UtilsConnection.decodeInfoConnection(info);
UtilsConnection.printInfoConnection($('.SPICE_info'), info_decode)
if (info_decode && info_decode.name) {
document.title = info_decode.name
}
// By default, use the host and port of server that served this file
host = spice_query_var('host', window.location.hostname);
var host = spice_query_var('host', window.location.hostname);
// Note that using the web server port only makes sense
// if your web server has a reverse proxy to relay the WebSocket
@ -57,20 +64,21 @@ define(function(require) {
default_port = 443;
}
}
port = spice_query_var('port', default_port);
var scheme = "ws://"
if (window.location.protocol == 'https:') {
scheme = "wss://";
}
// If a token variable is passed in, set the parameter in a cookie.
// This is used by nova-spiceproxy.
token = spice_query_var('token', null);
var token = spice_query_var('token', null);
if (token) {
spice_set_cookie('token', token, 1)
}
password = spice_query_var('password', '');
path = spice_query_var('path', 'websockify');
var password = spice_query_var('password', '');
var port = spice_query_var('port', default_port);
if ((!host) || (!port)) {
console.log("must specify host and port in URL");
@ -81,7 +89,7 @@ define(function(require) {
sc.stop();
}
uri = scheme + host + ":" + port + "?token=" + token;
var uri = scheme + host + ":" + port + "?token=" + token;
try {
sc = new SpiceMainConn({uri: uri, screen_id: "spice-screen", dump_id: "debug-div",
@ -91,7 +99,6 @@ define(function(require) {
alert(e.toString());
disconnect();
}
}
function disconnect() {

View File

@ -17,8 +17,10 @@
define(function(require) {
require("jquery");
require("jquery-ui");
var WMKS = require("wmks");
var Config = require("sunstone-config");
var UtilsConnection = require("utils/info-connection/utils");
var _wmks;
var _is_encrypted = "";
@ -38,16 +40,6 @@ define(function(require) {
setStatus("Something went wrong, connection is closed", "Failed");
}
}
function desktopNameChange(name) {
if (e.detail.name) {
setStatus(null, "VMRC " + _wmks.connectionState + " (" + _is_encrypted + ") to: " + name);
}
}
function credentialsRequired(e) {
setStatus("Something went wrong, more credentials must be given to continue", "Failed");
}
function sendCtrlAltDel() {
if (_wmks) { _wmks.sendCAD(); }
@ -95,7 +87,14 @@ define(function(require) {
var host = getQueryVariable("host");
var port = getQueryVariable("port");
var ticket = getQueryVariable("ticket");
var vm_name = getQueryVariable("name");
var info = spice_query_var('info', undefined);
var info_decode = UtilsConnection.decodeInfoConnection(info);
UtilsConnection.printInfoConnection($('.VMRC_info'), info_decode)
if (info_decode && info_decode.name) {
document.title = info_decode.name
}
if (window.location.protocol === "https:") {
URL = "wss";
@ -120,7 +119,7 @@ define(function(require) {
try{
_wmks = WMKS.createWMKS("wmksContainer", {})
.register(WMKS.CONST.Events.CONNECTION_STATE_CHANGE,
function (event, data) {
function (_, data) {
if (typeof cons !== 'undefined' && data.state == cons.ConnectionState.CONNECTED) {
console.log("connection state change : connected");
}
@ -129,9 +128,9 @@ define(function(require) {
_wmks.eventHandlers["connectionstatechange"].push(connected);
_wmks.eventHandlers["disconnect"] = disconnectedFromServer;
_wmks.vm_name = info_decode && info_decode.name;
_wmks.connect(URL);
_wmks["vm_name"] = vm_name;
}catch(err){
setStatus("Something went wrong, connection is closed", "Failed");
console.log("error start VMRC ", err);

View File

@ -15,11 +15,12 @@
/* -------------------------------------------------------------------------- */
define(function(require) {
var RFB = require("vnc-rfb").default;
var Config = require("sunstone-config");
var UtilsConnection = require("utils/info-connection/utils");
var RFB = require("vnc-rfb").default;
var _rfb;
var _is_encrypted = "";
var _vm_name;
function setStatus(message="", status=""){
$(".NOVNC_message").text(message);
@ -27,12 +28,12 @@ define(function(require) {
}
function connected(){
setStatus(null, "VNC " + _rfb._rfb_connection_state + " (" + _is_encrypted + ") to: " + (_vm_name || _rfb._fb_name));
setStatus(null, "VNC " + _rfb._rfb_connection_state + " (" + _is_encrypted + ") to: " + _rfb._fb_name);
}
function disconnectedFromServer(e){
if (e.detail.clean) {
setStatus(null, "VNC " + _rfb._rfb_connection_state + " (" + _is_encrypted + ") to: " + (_vm_name || _rfb._fb_name));
setStatus(null, "VNC " + _rfb._rfb_connection_state + " (" + _is_encrypted + ") to: " + _rfb._fb_name);
} else {
setStatus("Something went wrong, connection is closed", "Failed");
}
@ -40,7 +41,7 @@ define(function(require) {
function desktopNameChange(e) {
if (e.detail.name) {
setStatus(null, "VNC " + _rfb._rfb_connection_state + " (" + _is_encrypted + ") to: " + (_vm_name || e.detail.name));
setStatus(null, "VNC " + _rfb._rfb_connection_state + " (" + _is_encrypted + ") to: " + e.detail.name);
}
}
@ -127,13 +128,20 @@ define(function(require) {
}
return(false);
}
token = window.token;
var URL = "";
var proxy_host = window.location.hostname;
var proxy_port = Config.vncProxyPort;
var token = getQueryVariable("token");
var password = getQueryVariable("password");
_vm_name = getQueryVariable("title") || undefined;
var info = getQueryVariable('info') || undefined;
var info_decode = UtilsConnection.decodeInfoConnection(info);
UtilsConnection.printInfoConnection($('.NOVNC_info'), info_decode)
if (info_decode && info_decode.name) {
document.title = info_decode.name
}
var rfbConfig = password? { "credentials": { "password": password } } : {};

View File

@ -147,11 +147,49 @@ define(function(require) {
},
"STATES": STATES,
"filterDoneServices": _filterDoneServices,
"getService": _getService,
"getName": function(id){
return OpenNebulaAction.getName(id, CACHE_NAME);
}
}
function _promiseGetService({ id, success, async = true } = {}) {
return $.ajax({
url: 'service/' + id,
type: 'GET',
success: success,
async: async
});
}
function _getServiceById({ services, id } = {}) {
return Array.isArray(services) &&
services.find(function(service) {
return service && service[RESOURCE] && service[RESOURCE].ID === id
});
}
function _getService(id) {
if (!id) return undefined;
var service = undefined;
var cache = OpenNebulaAction.cache(CACHE_NAME);
if (cache && cache.data) {
service = _getServiceById({ services: cache.data, id: id })
}
if (!service || service.length === 0) {
_promiseGetService({
id: id,
async: false,
success: function(res) { service = res }
})
}
return service ? service[RESOURCE] : undefined
}
function _filterDoneServices(services) {
return $.grep(services, function(service) {
return service.DOCUMENT.TEMPLATE.BODY.state !== STATES.DONE;

View File

@ -29,6 +29,9 @@
</span>
</h5>
</div>
<div class="large-12 columns">
<div class="guac_info"></div>
</div>
</div>
<div id="guacamole-display" class="guacamole-display"></div>
</div>

View File

@ -19,19 +19,24 @@
<div class="large-12 columns">
<h3 class="subheader" id="spice_dialog">
{{tr "SPICE"}}
<span id="vnc_buttons">
<a id="open_in_a_new_window_spice" href="" target="_blank" title="{{tr "Open in a new window"}}"> <i class="fas fa-external-link-alt detach-spice-icon"/></a>
<span id="vnc_buttons" class="right">
<a class="button" id="open_in_a_new_window_spice" href="#" target="_blank" title="{{tr "Open in a new window"}}">
<i class="fas fa-external-link-alt detach-spice-icon"/>
</a>
<button class="button secondary" data-close aria-label="{{tr "Close modal"}}" aria-label="{{tr "Close modal"}}">
<i class="fas fa-times-circle"></i>
</button>
</span>
</h3>
</div>
<div class="large-12 columns">
<div class="SPICE_info"></div>
</div>
</div>
<div class="reveal-body" style="width:100%; overflow-x:auto">
<div id="spice-area">
<div id="spice-area" style="text-align: center; background: rgb(40, 40, 40);">
<div id="spice-screen" class="spice-screen"></div>
</div>
</div>
<div id="message-div" class="spice-message" hidden></div>
<button class="close-button" data-close aria-label="{{tr "Close modal"}}" type="button">
<span aria-hidden="true">&times;</span>
</button>
</div>

View File

@ -20,18 +20,21 @@
<h5 class="subheader" id="vmrc_dialog">
<span id="VMRC_status"></span>
<span id="VMRC_buttons" class="right">
<button class="button alert" value="Send CtrlAltDel"
id="sendCtrlAltDelButton">{{tr "Send CtrlAltDel"}}</button>
<a class="button" id="open_in_a_new_window" href="" target="_blank" title="{{tr "Open in a new window"}}">
<button class="button alert" id="sendCtrlAltDelButton">
{{tr "Send CtrlAltDel"}}
</button>
<a class="button" id="open_in_a_new_window" href="#" target="_blank" title="{{tr "Open in a new window"}}">
<i class="fas fa-external-link-alt detach-vmrc-icon" />
</a>
<button class="button secondary" data-close aria-label="{{tr "Close modal"}}" type="button"
title="Close VMRC">
<button class="button secondary" data-close aria-label="{{tr "Close modal"}}" title="{{tr "Close VMRC"}}">
<i class="fas fa-times-circle"></i>
</button>
</span>
</h5>
</div>
<div class="large-12 columns">
<div class="VMRC_info"></div>
</div>
</div>
<div class="reveal-body text-center" style="width:100%; overflow-x:auto">
<div id="wmksContainer" style="position:absolute;width:100%;height:100%; left:0em"></div>

View File

@ -15,21 +15,26 @@
{{! -------------------------------------------------------------------------- }}
<div id="{{dialogId}}" class="reveal full" data-reveal>
<div class="row text-center">
<div class="row">
<div class="large-12 columns">
<h5 class="subheader" id="vnc_dialog">
<span id="VNC_status"></span>
<span id="VNC_buttons" class="right">
<button class="button alert" value="Send CtrlAltDel" id="sendCtrlAltDelButton">{{tr "Send CtrlAltDel"}}</button>
<a class="button" id="open_in_a_new_window" href="" target="_blank" title="{{tr "Open in a new window"}}">
<button class="button alert" id="sendCtrlAltDelButton">
{{tr "Send CtrlAltDel"}}
</button>
<a class="button" id="open_in_a_new_window" href="#" target="_blank" title="{{tr "Open in a new window"}}">
<i class="fas fa-external-link-alt detach-vnc-icon"/>
</a>
<button class="button secondary" data-close aria-label="{{tr "Close modal"}}" type="button" title="Close VNC">
<button class="button secondary" data-close aria-label="{{tr "Close modal"}}" title="{{tr "Close VNC"}}">
<i class="fas fa-times-circle"></i>
</button>
</span>
</h5>
</div>
<div class="large-12 columns">
<div class="NOVNC_info"></div>
</div>
</div>
<div class="reveal-body text-center" style="width:100%; overflow-x:auto">
<div id="VNC_canvas" width="640px">

View File

@ -22,6 +22,7 @@ define(function(require) {
var Config = require("sunstone-config");
var Notifier = require("utils/notifier");
var Locale = require("utils/locale");
var UtilsConnection = require("utils/info-connection/utils");
/**
* CONSTRUCTOR
@ -74,7 +75,9 @@ define(function(require) {
var tunnel = new Guacamole.WebSocketTunnel(wsprotocol + '//' + host + ':' + port + '/fireedge/guacamole')
var guac = this._client = new Guacamole.Client(tunnel);
var vm_name = response.vm_name || "";
var info_decode = UtilsConnection.decodeInfoConnection(response.info);
UtilsConnection.printInfoConnection($('.guac_info'), info_decode)
// Client display
this._display = $("#guacamole-display");
@ -97,19 +100,19 @@ define(function(require) {
guac.onstatechange = function(state) {
switch (state) {
case 0:
setStatus("Client IDLE to: " + vm_name);
setStatus('Client IDLE');
setLoading(true);
break;
case 1:
setStatus("Client CONNECTING to: " + vm_name);
setStatus('Client CONNECTING');
setLoading(true);
break;
case 2:
setStatus("Client WAITING to: " + vm_name);
setStatus('Client WAITING');
setLoading(true);
break;
case 3:
setStatus("Client CONNECTED to: " + vm_name);
setStatus('Client CONNECTED');
setLoading(false);
setTimeout(function() {
rescale(that);
@ -117,15 +120,15 @@ define(function(require) {
}, 100);
break;
case 4:
setStatus("Client DISCONNECTING to: " + vm_name);
setStatus('Client DISCONNECTING');
setLoading(true);
break;
case 5:
setStatus("Client DISCONNECTED to: " + vm_name);
setStatus('Client DISCONNECTED');
setLoading(false);
break;
default:
setStatus("Client ERROR to: " + vm_name);
setStatus('Client ERROR');
setLoading(false);
break;
}

View File

@ -0,0 +1,83 @@
{{! -------------------------------------------------------------------------- }}
{{! Copyright 2002-2021, 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. }}
{{! -------------------------------------------------------------------------- }}
<div style="
color: #000000;
font-weight: 300;
line-height: 1.4;
font-size: 1.3rem;
display: flex;
flex-wrap: wrap;
gap: 1rem;
align-items: center;
margin: 1rem 0;
">
<div style="
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
flex-grow: 1;
">
{{!-- STATE --}}
<span title="{{state}}" class="badge {{stateClass}}" style="min-width: auto;font-size: inherit;"></span>
{{!-- ID - NAME --}}
<span>#{{ id }} - {{ name }}</span>
{{!-- SERVICE --}}
{{#if service }}
<span>(Part of: {{ service.NAME }})</span>
{{/if}}
</div>
{{!-- START TIME --}}
<div>
<span>Started on: {{ humanizeTime start_time }}</span>
</div>
{{!-- NETWORKS --}}
{{#ifEquals networks.length 0 }}
{{!-- dont render when if 0 --}}
{{else}}
<div>
{{#ifEquals networks.length 1 }}
<span>
{{#each networks}} {{#if @first}} {{ this }} {{/if}} {{/each}}
</span>
{{else}}
<ul class="dropdown menu ips-dropdown" data-dropdown-menu>
<li>
<a style="color: #000000">
{{#each networks}} {{#if @first}} {{ this }} {{/if}} {{/each}}
</a>
<ul class="menu" style="
max-height: 10em;
max-width: 12em;
overflow-y: auto;
">
{{#each networks}}
<li>
<a style="color:gray">{{ this }}</a>
</li>
{{/each}}
</ul>
</li>
</ul>
{{/ifEquals}}
</div>
{{/ifEquals}}
</div>

View File

@ -0,0 +1,57 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2021, 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) {
require('foundation')
var OpenNebulaVM = require('opennebula/vm');
var OpenNebulaService = require('opennebula/service');
var TemplateInfo = require('hbs!./info');
function printInfoConnection(context, info) {
context.empty()
info && context.append(TemplateInfo(info))
$('.ips-dropdown').foundation()
}
function decodeInfoConnection(info_encode) {
if (!info_encode) return undefined
try {
var json = atob(info_encode)
var info = JSON.parse(json)
// state class
var stateId = OpenNebulaVM.STATES[info.state]
var lcmStateId = OpenNebulaVM.LCM_STATES[info.state]
var stateClass = OpenNebulaVM.stateClass(stateId) || OpenNebulaVM.lcmStateClass(lcmStateId)
// get service from cache or sync
var service = OpenNebulaService.getService(info.service_id)
return $.extend(info, { stateClass, service })
} catch (err) {
console.log(err)
}
}
return {
'printInfoConnection': printInfoConnection,
'decodeInfoConnection': decodeInfoConnection
}
});

View File

@ -44,6 +44,8 @@ define(function(require) {
tr("November"), tr("December"));
function tr(str) {
if (typeof locale === 'undefined') return str;
var tmp = locale[str];
if (tmp == null || tmp == "") {
tmp = str;

View File

@ -16,8 +16,9 @@
define(function(require) {
require('spice-main');
var Config = require('sunstone-config');
var Notifier = require('utils/notifier');
var UtilsConnection = require("utils/info-connection/utils");
var _lock = false;
var _sc;
@ -42,14 +43,16 @@ define(function(require) {
_lock = false;
}
function spice_error(e) {
function spice_error() {
disconnect();
}
function disconnect() {
if (_sc) {
_sc.stop();
}
try {
if (_sc) {
_sc.stop();
}
} catch (e) {}
}
function agent_connected(sc) {
@ -60,26 +63,26 @@ define(function(require) {
}
function spiceCallback(response) {
var host, port, password, scheme = "ws://", uri, token, vm_name;
var scheme = "ws://";
if (Config.vncWSS == "yes") {
scheme = "wss://";
}
host = window.location.hostname;
port = Config.vncProxyPort;
password = response["password"];
token = response["token"];
vm_name = response["vm_name"];
var host = window.location.hostname;
var port = Config.vncProxyPort;
var password = response["password"];
var token = response["token"];
var info = response.info;
var info_decode = UtilsConnection.decodeInfoConnection(info);
UtilsConnection.printInfoConnection($('.SPICE_info'), info_decode)
if ((!host) || (!port)) {
console.log("must specify host and port in URL");
return;
}
if (_sc) {
_sc.stop();
}
disconnect()
uri = scheme + host + ":" + port + "?token=" + token;
@ -88,7 +91,7 @@ define(function(require) {
message_id: "message-div", password: password, onerror: spice_error, onagent: agent_connected});
}
catch (e) {
spice_error(e)
disconnect()
}
var url = "spice?";
@ -97,7 +100,7 @@ define(function(require) {
url += "&token=" + token;
url += "&password=" + password;
url += "&encrypt=" + config['user_config']['vnc_wss'];
url += "&title=" + vm_name;
url += "&info=" + info;
$("#open_in_a_new_window_spice").attr('href', url);
}

View File

@ -17,6 +17,8 @@
define(function (require) {
var WMKS = require("wmks");
var Config = require("sunstone-config");
var UtilsConnection = require("utils/info-connection/utils");
var _lock = false;
var _wmks;
var _is_encrypted = "";
@ -59,19 +61,7 @@ define(function (require) {
}
}
function desktopNameChange(e) {
if (e.detail.name) {
setStatus(null, "VMRC " + _wmks.connectionState + " (" + _is_encrypted + ") to: " /*+ e.detail.name*/);
}
}
function credentialsRequired(e) {
setStatus("Something went wrong, more credentials must be given to continue", "Failed");
}
function render(ticket, host_vmrc, port_vmrc, response){
var URL = "";
var hostname = window.location.hostname;
var port = window.location.port;
var protocol = window.location.protocol;
@ -79,14 +69,19 @@ define(function (require) {
var fireedge_host = fireedge_endpoint.split(":")[0];
var fireedge_port = fireedge_endpoint.split(":")[1];
var info = response.info;
var info_decode = UtilsConnection.decodeInfoConnection(info);
UtilsConnection.printInfoConnection($('.VMRC_info'), info_decode)
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
// Content of response.data
var ticket = ticket ? ticket : urlParams.get('ticket');
var host_vmrc = host_vmrc ? host_vmrc : urlParams.get('host');
var port_vmrc = port_vmrc ? port_vmrc : urlParams.get('port');
var ticket = ticket || urlParams.get('ticket');
var host_vmrc = host_vmrc || urlParams.get('host');
var port_vmrc = port_vmrc || urlParams.get('port');
var URL = "";
if (protocol === "https:") {
URL = "wss";
_is_encrypted ="encrypted";
@ -97,20 +92,21 @@ define(function (require) {
URL += "://" + fireedge_endpoint + "/";
var re = new RegExp("^(ws|wss):\\/\\/[\\w\\D]*?\\/", "gi");
var link = URL.replace(re, protocol + "//" + hostname + ":" + port + "fireedge/vmrc?");
var regex = new RegExp("^(ws|wss):\\/\\/[\\w\\D]*?\\/", "gi");
var link = URL.replace(regex, protocol + "//" + hostname + ":" + port + "fireedge/vmrc?");
URL += "fireedge/vmrc/" + ticket;
link += "host=" + fireedge_host;
link += "&port=" + fireedge_port;
link += "&ticket=" + ticket;
link += "&info=" + info;
try {
_wmks = WMKS.createWMKS("wmksContainer", {})
_wmks = WMKS.createWMKS('wmksContainer', {})
.register(WMKS.CONST.Events.CONNECTION_STATE_CHANGE,
function (event, data) {
if (typeof cons !== 'undefined' && data.state == cons.ConnectionState.CONNECTED) {
console.log("connection state change : connected");
function (_, data) {
if (data.state === WMKS.CONST.ConnectionState.CONNECTED) {
console.log("connection state change: connected");
}
}
);
@ -119,9 +115,9 @@ define(function (require) {
_wmks.eventHandlers["disconnect"] = disconnectedFromServer;
_wmks.connect(URL);
_wmks["vm_name"] = response.vm_name ? response.vm_name:"";
link += "&name=" + _wmks["vm_name"];
$("#VMRC_buttons #open_in_a_new_window").attr("href",link);
} catch (err) {
setStatus("Something went wrong, connection is closed", "Failed");
console.log("error start VMRC ", err);
@ -129,14 +125,13 @@ define(function (require) {
}
function vmrcCallback(response) {
if (response.data){
render(response.data.ticket,
if (response.data) {
render(
response.data.ticket,
response.data.host,
response.data.port,
response);
response
);
}
}

View File

@ -15,14 +15,15 @@
/* -------------------------------------------------------------------------- */
define(function(require) {
var RFB = require("vnc-rfb").default;
var Config = require("sunstone-config");
var UtilsConnection = require("utils/info-connection/utils");
var RFB = require("vnc-rfb").default;
var _lock = false;
var _rfb;
var _message = "";
var _status = "Loading";
var _is_encrypted = "";
var _vm_name;
return {
"lockStatus": lockStatus,
@ -51,14 +52,14 @@ define(function(require) {
$(".NOVNC_message").text(_message);
$("#VNC_status").text(_status);
}
function connected(){
setStatus(null, "VNC " + _rfb._rfb_connection_state + " (" + _is_encrypted + ") to: " + (_vm_name || _rfb._fb_name));
setStatus(null, "VNC " + _rfb._rfb_connection_state + " (" + _is_encrypted + ") to: " + _rfb._fb_name);
}
function disconnectedFromServer(e){
if (e.detail.clean) {
setStatus(null, "VNC " + _rfb._rfb_connection_state + " (" + _is_encrypted + ") to: " + (_vm_name || _rfb._fb_name));
setStatus(null, "VNC " + _rfb._rfb_connection_state + " (" + _is_encrypted + ") to: " + _rfb._fb_name);
} else {
setStatus("Something went wrong, connection is closed", "Failed");
}
@ -76,15 +77,20 @@ define(function(require) {
function vncCallback(response) {
var URL = "";
var proxy_host = window.location.hostname;
var proxy_port = Config.vncProxyPort;
var pw = response["password"];
var token = response["token"];
var vm_name = _vm_name = response["vm_name"];
var pw = response.password;
var token = response.token;
var info_decode = UtilsConnection.decodeInfoConnection(response.info);
UtilsConnection.printInfoConnection($('.NOVNC_info'), info_decode)
var proxy_host = window.location.hostname;
var protocol = window.location.protocol;
var hostname = window.location.hostname;
var port = window.location.port;
var rfbConfig = pw? { "credentials": { "password": pw } } : {};
var rfbConfig = pw ? { "credentials": { "password": pw } } : {};
if (protocol === "https:") {
URL = "wss";
@ -99,7 +105,7 @@ define(function(require) {
URL += "&port=" + proxy_port;
URL += "&token=" + token;
URL += "&encrypt=" + Config.vncWSS;
URL += "&title=" + vm_name;
URL += "&info=" + response.info;
if (!Config.requestVNCPassword) {
URL += "&password=" + pw;

View File

@ -36,8 +36,6 @@ html {
#noVNC_password {
width: 150px;
}
#noVNC_encrypt {
}
#noVNC_path {
width: 100px;
}
@ -85,11 +83,7 @@ html {
}
#noVNC_status {
font-size: 12px;
padding-top: 4px;
height:32px;
text-align: center;
font-weight: bold;
}
#noVNC_settings_menu {
@ -114,7 +108,6 @@ html {
height: 36px;
}
#noVNC_screen {
text-align: center;
width: 100%;
display: inline-flex;
height: 100%;
@ -395,10 +388,8 @@ html {
}
#noVNC_status {
z-index: 0;
position: absolute;
width: 100%;
margin-left: 0px;
}
#showExtraKeysButton { display: none; }
@ -414,7 +405,6 @@ html {
position: relative;
width: auto;
float: left;
margin-left: 4px;
}
}

View File

@ -8,13 +8,18 @@ body
* { margin: 0; }
#spice-area
{
main {
height: 100%;
padding: 0;
margin-left: auto;
margin-right: auto;
display: grid;
grid-template-rows: auto 1fr;
}
#spice-area {
display: flex;
background-color: rgb(40, 40, 40);
align-items: center;
}
.spice-screen
{
min-height: 600px;

View File

@ -258,13 +258,13 @@ if $conf[:webauthn_avail]
end
#start VNC proxy
$vnc = OpenNebulaVNC.new($conf, logger)
$vnc = SunstoneVNC.new($conf, logger)
#init Guacamole server
$guac = OpenNebulaGuac.new(logger)
$guac = SunstoneGuac.new(logger)
#init VMRC server
$vmrc = OpenNebulaVMRC.new(logger)
$vmrc = SunstoneVMRC.new(logger)
configure do
set :run, false
@ -709,10 +709,10 @@ get '/vnc' do
erb :login
else
erb :vnc, :locals => {
:logos_conf => $conf[:locals][:logos_conf],
:oned_conf => $conf[:locals][:oned_conf],
:support => $conf[:locals][:support],
:upgrade => $conf[:locals][:upgrade]
:logos_conf => $conf[:locals][:logos_conf],
:oned_conf => $conf[:locals][:oned_conf],
:support => $conf[:locals][:support],
:upgrade => $conf[:locals][:upgrade]
}
end
end
@ -723,10 +723,10 @@ get '/vmrc' do
erb :login
else
erb :vmrc, :locals => {
:logos_conf => $conf[:locals][:logos_conf],
:oned_conf => $conf[:locals][:oned_conf],
:support => $conf[:locals][:support],
:upgrade => $conf[:locals][:upgrade]
:logos_conf => $conf[:locals][:logos_conf],
:oned_conf => $conf[:locals][:oned_conf],
:support => $conf[:locals][:support],
:upgrade => $conf[:locals][:upgrade]
}
end
end
@ -736,8 +736,12 @@ get '/spice' do
if !authorized?
erb :login
else
params[:title] = CGI::escape(params[:title])
erb :spice
erb :spice, :locals => {
:logos_conf => $conf[:locals][:logos_conf],
:oned_conf => $conf[:locals][:oned_conf],
:support => $conf[:locals][:support],
:upgrade => $conf[:locals][:upgrade]
}
end
end

View File

@ -26,36 +26,81 @@
<!doctype html>
<html>
<head>
<head>
<!-- Stylesheets -->
<link rel="stylesheet" type="text/css" href="css/app.css" title="plain">
<link rel="stylesheet" type="text/css" href="css/spice-custom.css" />
</head>
<title><%= params['title']%></title>
<link rel="stylesheet" type="text/css" href="css/spice-custom.css" />
<script src="dist/console/spice.js?v=<%= OpenNebula::VERSION %>"></script>
</head>
<body>
<div style="background: #f7f7f7; border-bottom: 1px solid #dfdfdf; padding: 10px 0px 15px 0px">
<div id="noVNC_status_bar" class="noVNC_status_bar" style="margin-top: 0px;">
<table border=0 width="100%"><tr>
<td width="1%" >
<img src="images/one_small_logo.png" style="height:40px; vertical-align:top; margin-left: 30px">
</td>
<td><div id="message-div" class="spice-message"></div></td>
</tr></table>
</div>
<body>
<main>
<div style="background: #f7f7f7; padding: 1.5em 1.5em 0.8em;">
<div style="max-width: 1250px; margin: 0 auto;">
<div id="noVNC_status_bar" class="noVNC_status_bar" style="display: flex; align-items: center;">
<img src="images/one_small_logo.png" style="height:40px;">
<h5 id="message-div" class="spice-message"></h5>
</div>
<div class="SPICE_info"></div>
</div>
</div>
<div id="spice-area">
<div id="spice-screen" class="spice-screen"></div>
</div>
<div id="spice-area">
<div id="spice-screen" class="spice-screen"></div>
</div>
<div id="debug-div">
<!-- If DUMPXXX is turned on, dumped images will go here -->
</div>
</main>
<div id="debug-div">
<!-- If DUMPXXX is turned on, dumped images will go here -->
</div>
</body>
<script src="dist/console/spice.js?v=<%= OpenNebula::VERSION %>"></script>
<% view = $views_config.view(session[:user], session[:user_gname], session[:default_view]) %>
<script type="text/javascript">
var csrftoken = '<%= session[:csrftoken] %>';
var view = JSON.parse('<%= view.to_json %>')
var available_views = JSON.parse('["<%=
$views_config.available_views(session[:user], session[:user_gname]).join('","')
%>"]')
var all_labels = JSON.parse('["<%=
$views_config.get_all_labels(session[:user_gname]).join('","')
%>"]')
var all_views = JSON.parse('["<%=
$views_config.get_all_views.join('","')
%>"]')
if ('<%= $conf[:addons] %>'){
var addons = JSON.parse('<%= $conf[:addons].to_json %>');
}
var config = {
'user_config' : {
'lang' : '<%= session[:lang] %>',
'vnc_wss' : '<%= session[:vnc_wss] %>',
'table_order' : '<%= session[:table_order] %>',
'default_view' : '<%= session[:default_view] %>',
'page_length' : '<%= session[:page_length] %>'
},
'system_config' : {
'marketplace_url' : '<%= $conf[:marketplace_url] %>',
'vnc_request_password' : <%= $conf[:vnc_request_password] || false %>,
'vnc_proxy_port' : '<%= $vnc.proxy_port %>',
'vnc_client_port' : '<%= $conf[:vnc_client_port] %>',
'max_upload_file_size' : <%= $conf[:max_upload_file_size] ? $conf[:max_upload_file_size] : "undefined" %>
},
'view' : view,
'available_views' : available_views,
'all_labels' : all_labels,
'all_views' : all_views,
'user_id' : '<%= session[:user_id] %>',
'user_gid' : '<%= session[:user_gid] %>',
'display_name' : '<%= session[:display_name] %>',
'zone_name' : '<%= session[:zone_name] %>',
'zone_id' : '<%= session[:zone_id] %>',
'federation_mode' : '<%= session[:federation_mode] %>',
'vm_logos' : <%= logos_conf.to_json %>,
'oned_conf' : <%= oned_conf.to_json %>,
'support' : <%= support.to_json %>,
'upgrade' : <%= upgrade.to_json %>,
'mode' : '<%= session[:mode] %>'
};
</script>
</body>
</html>

View File

@ -1,97 +1,89 @@
<!DOCTYPE html>
<html>
<head>
<title><%= params['vm_name']%></title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<link rel="apple-touch-startup-image" href="images/screen_320x460.png" />
<link rel="apple-touch-icon" href="images/screen_57x57.png">
<!-- Stylesheets -->
<link rel="stylesheet" type="text/css" href="css/novnc-custom.css" title="plain">
<% view = $views_config.view(session[:user], session[:user_gname], session[:default_view]) %>
<script type="text/javascript">
var csrftoken = '<%= session[:csrftoken] %>';
var view = JSON.parse('<%= view.to_json %>')
var available_views = JSON.parse('["<%=
$views_config.available_views(session[:user], session[:user_gname]).join('","')
%>"]')
var all_labels = JSON.parse('["<%=
$views_config.get_all_labels(session[:user_gname]).join('","')
%>"]')
var all_views = JSON.parse('["<%=
$views_config.get_all_views.join('","')
%>"]')
if ('<%= $conf[:addons] %>'){
var addons = JSON.parse('<%= $conf[:addons].to_json %>');
}
var config = {
'user_config' : {
'lang' : '<%= session[:lang] %>',
'vnc_wss' : '<%= session[:vnc_wss] %>',
'table_order' : '<%= session[:table_order] %>',
'default_view' : '<%= session[:default_view] %>',
'page_length' : '<%= session[:page_length] %>'
},
'system_config' : {
'marketplace_url' : '<%= $conf[:marketplace_url] %>',
'vnc_request_password' : <%= $conf[:vnc_request_password] || false %>,
'vnc_proxy_port' : '<%= $vnc.proxy_port %>',
'vnc_client_port' : '<%= $conf[:vnc_client_port] %>',
'max_upload_file_size' : <%= $conf[:max_upload_file_size] ? $conf[:max_upload_file_size] : "undefined" %>
},
'view' : view,
'available_views' : available_views,
'all_labels' : all_labels,
'all_views' : all_views,
'user_id' : '<%= session[:user_id] %>',
'user_gid' : '<%= session[:user_gid] %>',
'display_name' : '<%= session[:display_name] %>',
'zone_name' : '<%= session[:zone_name] %>',
'zone_id' : '<%= session[:zone_id] %>',
'federation_mode' : '<%= session[:federation_mode] %>',
'vm_logos' : <%= logos_conf.to_json %>,
'oned_conf' : <%= oned_conf.to_json %>,
'support' : <%= support.to_json %>,
'upgrade' : <%= upgrade.to_json %>,
'mode' : '<%= session[:mode] %>'
};
</script>
<script src="dist/console/vnc.js?v=<%= OpenNebula::VERSION %>"></script>
</head>
<body style="margin: 0px;">
<div id="noVNC_screen">
<div style="background: #f7f7f7; border-bottom: 1px solid #dfdfdf; padding: 10px 0px 15px 0px">
<div id="noVNC_status_bar" class="noVNC_status_bar" style="margin-top: 0px;">
<table border=0 width="100%">
<tr>
<td width="1%" >
<img src="images/one_small_logo.png" style="height:40px; vertical-align:top; margin-left: 30px"></td>
<td>
<div id="noVNC_status" style="position: relative; height: auto; color: #000;">Loading</div>
</td>
<td width="1%" >
<div id="noVNC_buttons" style="margin-right: 30px">
<input type=button value="Send CtrlAltDel"
id="sendCtrlAltDelButton">
<span id="noVNC_xvp_buttons">
<input type=button value="Shutdown"
id="xvpShutdownButton">
<input type=button value="Reboot"
id="xvpRebootButton">
<input type=button value="Reset"
id="xvpResetButton"></span>
</div>
</td>
</tr>
</table>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<link rel="apple-touch-startup-image" href="images/screen_320x460.png" />
<link rel="apple-touch-icon" href="images/screen_57x57.png">
<!-- Stylesheets -->
<link rel="stylesheet" type="text/css" href="css/app.css" title="plain">
<link rel="stylesheet" type="text/css" href="css/novnc-custom.css" title="plain">
</head>
<body>
<div id="noVNC_screen">
<div style="background: #f7f7f7; padding: 1.5em 1.5em 0.8em;">
<div style="max-width: 1250px; margin: 0 auto;">
<div id="noVNC_status_bar" class="noVNC_status_bar" style="display: flex; align-items: center;">
<img src="images/one_small_logo.png" style="height:40px;">
<h5 id="noVNC_status" style="position: relative;">Loading</h5>
<div id="noVNC_buttons">
<button class="button alert" id="sendCtrlAltDelButton">Send CtrlAltDel</button>
<span id="noVNC_xvp_buttons">
<input type=button value="Shutdown" id="xvpShutdownButton">
<input type=button value="Reboot" id="xvpRebootButton">
<input type=button value="Reset" id="xvpResetButton">
</span>
</div>
</div>
<div id="VNC_canvas" width="640px" height="20px">
<div class="NOVNC_message"></div>
</div>
<div class="NOVNC_info"></div>
</div>
</body>
</html>
</div>
<div id="VNC_canvas" width="640px" height="20px">
<div class="NOVNC_message"></div>
</div>
</div>
<script src="dist/console/vnc.js?v=<%= OpenNebula::VERSION %>"></script>
<% view = $views_config.view(session[:user], session[:user_gname], session[:default_view]) %>
<script type="text/javascript">
var csrftoken = '<%= session[:csrftoken] %>';
var view = JSON.parse('<%= view.to_json %>')
var available_views = JSON.parse('["<%=
$views_config.available_views(session[:user], session[:user_gname]).join('","')
%>"]')
var all_labels = JSON.parse('["<%=
$views_config.get_all_labels(session[:user_gname]).join('","')
%>"]')
var all_views = JSON.parse('["<%=
$views_config.get_all_views.join('","')
%>"]')
if ('<%= $conf[:addons] %>'){
var addons = JSON.parse('<%= $conf[:addons].to_json %>');
}
var config = {
'user_config' : {
'lang' : '<%= session[:lang] %>',
'vnc_wss' : '<%= session[:vnc_wss] %>',
'table_order' : '<%= session[:table_order] %>',
'default_view' : '<%= session[:default_view] %>',
'page_length' : '<%= session[:page_length] %>'
},
'system_config' : {
'marketplace_url' : '<%= $conf[:marketplace_url] %>',
'vnc_request_password' : <%= $conf[:vnc_request_password] || false %>,
'vnc_proxy_port' : '<%= $vnc.proxy_port %>',
'vnc_client_port' : '<%= $conf[:vnc_client_port] %>',
'max_upload_file_size' : <%= $conf[:max_upload_file_size] ? $conf[:max_upload_file_size] : "undefined" %>
},
'view' : view,
'available_views' : available_views,
'all_labels' : all_labels,
'all_views' : all_views,
'user_id' : '<%= session[:user_id] %>',
'user_gid' : '<%= session[:user_gid] %>',
'display_name' : '<%= session[:display_name] %>',
'zone_name' : '<%= session[:zone_name] %>',
'zone_id' : '<%= session[:zone_id] %>',
'federation_mode' : '<%= session[:federation_mode] %>',
'vm_logos' : <%= logos_conf.to_json %>,
'oned_conf' : <%= oned_conf.to_json %>,
'support' : <%= support.to_json %>,
'upgrade' : <%= upgrade.to_json %>,
'mode' : '<%= session[:mode] %>'
};
</script>
</body>
</html>