1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-01-11 05:17:41 +03:00

F #2755: Fireedge guacamole connection (#265)

* Linting Guacamole
* Guacamole with fireedge
* Guacd start with fireedge
This commit is contained in:
Frederick Borges 2020-09-29 14:26:48 +02:00 committed by GitHub
parent 313b74e651
commit 01653bdcf1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 451 additions and 536 deletions

View File

@ -904,7 +904,7 @@ RUBY_LIB_FILES="src/mad/ruby/ActionManager.rb \
src/vnm_mad/one_vnm.rb \
src/oca/ruby/opennebula.rb \
src/sunstone/OpenNebulaVNC.rb \
src/sunstone/OpenNebulaGuac.rb \
src/sunstone/opennebula_guac.rb \
src/sunstone/opennebula_vmrc.rb \
src/sunstone/OpenNebulaAddons.rb \
src/vmm_mad/remotes/vcenter/vcenter_driver.rb \

View File

@ -237,7 +237,6 @@ AllCops:
- src/authm_mad/remotes/x509/x509_auth.rb
- src/authm_mad/remotes/ssh/ssh_auth.rb
- src/sunstone/sunstone-server.rb
- src/sunstone/OpenNebulaGuac.rb
- src/sunstone/test/spec/spec_helper.rb
- src/sunstone/test/spec/vnet_spec.rb
- src/sunstone/test/spec/image_spec.rb

View File

@ -22,14 +22,34 @@ if [ -z "$ONE_LOCATION" ]; then
FIREEDGE_LOCK_FILE=/var/lock/one/.fireedge.lock
FIREEDGE_LOG=/var/log/one/fireedge.log
FIREEDGE_LOG_ERROR=/var/log/one/fireedge.error
GUACD_PID=/var/run/one/guacd.pid
else
FIREEDGE_PID=$ONE_LOCATION/var/fireedge.pid
FIREEDGE_SERVER=$ONE_LOCATION/lib/fireedge/dist/index.js
FIREEDGE_LOCK_FILE=$ONE_LOCATION/var/.fireedge.lock
FIREEDGE_LOG=$ONE_LOCATION/var/fireedge.log
FIREEDGE_LOG_ERROR=$ONE_LOCATION/var/fireedge.error
GUACD_PID=$ONE_LOCATION/var/guacd.pid
fi
GUACD_BIN=guacd
get_pid()
{
if [ -f "$1" ]; then
read PID < "$1"
# if pidfile contains PID and PID is valid
if [ -n "$PID" ] && ps "$PID" > /dev/null 2>&1; then
echo "$PID"
return 0
fi
fi
# pidfile/pid not found, or process is dead
return 1
}
setup()
{
if [ -f $FIREEDGE_LOCK_FILE ]; then
@ -56,7 +76,7 @@ start()
touch $FIREEDGE_LOCK_FILE
# Start the oneflow-server daemon
# Start the fireedge-server daemon
node $FIREEDGE_SERVER >$FIREEDGE_LOG 2>$FIREEDGE_LOG_ERROR &
LASTRC=$?
@ -74,8 +94,8 @@ start()
ps $LASTPID > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error executing fireedge-server."
echo "Check $FIREEDGE_LOG_ERROR and $FIREEDGE_LOG for more information"
echo "Error executing fireedge-server."
echo "Check $FIREEDGE_LOG_ERROR and $FIREEDGE_LOG for more information"
exit 1
fi
}
@ -96,18 +116,71 @@ stop()
rm -f $FIREEDGE_LOCK_FILE &> /dev/null
}
start_guacd()
{
if [ ! -f "$GUACD_BIN" ]; then
echo "Cannot find $GUACD_BIN."
return 1
fi
PID=`get_pid $GUACD_PID`
if [ $? -eq 0 ]; then
echo "Guacamole proxy daemon already running"
return 1
fi
echo -n "Starting guacd: "
$GUACD_BIN -p "$GUACD_PID" > /dev/null 2>&1
case "$?" in
0)
echo "SUCCESS"
;;
*)
echo "FAIL"
;;
esac
}
stop_guacd()
{
echo -n "Stopping guacd: "
PID=`get_pid $GUACD_PID`
case "$?" in
0)
if kill -9 $PID > /dev/null 2>&1
then
echo "SUCCESS"
return 0
fi
echo "FAIL"
return 0
;;
*)
echo "SUCCESS (not running)"
return 0
;;
esac
}
case "$1" in
start)
start_guacd
setup
start
echo "fireedge-server started"
;;
stop)
stop_guacd
stop
echo "fireedge-server stopped"
;;
restart)
stop_guacd 2> /dev/null
stop 2> /dev/null
start_guacd
setup
start
echo "fireedge-server restarted"

View File

@ -1,325 +0,0 @@
# -------------------------------------------------------------------------- #
# 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. #
#--------------------------------------------------------------------------- #
#
# This class provides support for launching and stopping a websockify proxy
#
require 'rubygems'
require 'json'
require 'opennebula'
require 'base64'
require 'openssl'
if !ONE_LOCATION
GUAC_LOCK_FILE = "/var/lock/one/.guac.lock"
GUACD_PID_FILE = "/var/run/one/guacd.pid"
else
GUAC_LOCK_FILE= ONE_LOCATION + "/var/.guac.lock"
GUACD_PID_FILE= ONE_LOCATION + "/var/guacd.pid"
end
GUAC_STATES = [
#0, #LCM_INIT
#1, #PROLOG
#2, #BOOT
"3", #RUNNING
"4", #MIGRATE
#5, #SAVE_STOP
#6, #SAVE_SUSPEND
#7, #SAVE_MIGRATE
#8, #PROLOG_MIGRATE
#9, #PROLOG_RESUME
#10, #EPILOG_STOP
#11, #EPILOG
"12", #SHUTDOWN
"13", #CANCEL
#14, #FAILURE
#15, #CLEANUP_RESUBMIT
"16", #UNKNOWN
"17", #HOTPLUG
"18", #SHUTDOWN_POWEROFF
#19, #BOOT_UNKNOWN
#20, #BOOT_POWEROFF
#21, #BOOT_SUSPENDED
#22, #BOOT_STOPPED
#23, #CLEANUP_DELETE
"24", #HOTPLUG_SNAPSHOT
"25", #HOTPLUG_NIC
"26", #HOTPLUG_SAVEAS
"27", #HOTPLUG_SAVEAS_POWEROFF
"28", #HOTPLUG_SAVEAS_SUSPENDED
"29", #SHUTDOWN_UNDEPLOY
#30, #EPILOG_UNDEPLOY
#31, #PROLOG_UNDEPLOY
#32, #BOOT_UNDEPLOY
#33, #HOTPLUG_PROLOG_POWEROFF
#34, #HOTPLUG_EPILOG_POWEROFF
#35, #BOOT_MIGRATE
#36, #BOOT_FAILURE
#37, #BOOT_MIGRATE_FAILURE
#38, #PROLOG_MIGRATE_FAILURE
#39, #PROLOG_FAILURE
#40, #EPILOG_FAILURE
#41, #EPILOG_STOP_FAILURE
#42, #EPILOG_UNDEPLOY_FAILURE
#43, #PROLOG_MIGRATE_POWEROFF
#44, #PROLOG_MIGRATE_POWEROFF_FAILURE
#45, #PROLOG_MIGRATE_SUSPEND
#46, #PROLOG_MIGRATE_SUSPEND_FAILURE
#47, #BOOT_UNDEPLOY_FAILURE
#48, #BOOT_STOPPED_FAILURE
#49, #PROLOG_RESUME_FAILURE
#50, #PROLOG_UNDEPLOY_FAILURE
#51, #DISK_SNAPSHOT_POWEROFF
#52, #DISK_SNAPSHOT_REVERT_POWEROFF
#53, #DISK_SNAPSHOT_DELETE_POWEROFF
#54, #DISK_SNAPSHOT_SUSPENDED
#55, #DISK_SNAPSHOT_REVERT_SUSPENDED
#56, #DISK_SNAPSHOT_DELETE_SUSPENDED
"57", #DISK_SNAPSHOT
"58", #DISK_SNAPSHOT_REVERT
#59, #DISK_SNAPSHOT_DELETE
#60, #PROLOG_MIGRATE_UNKNOWN
#61, #PROLOG_MIGRATE_UNKNOWN_FAILURE
"62" #DISK_RESIZE
#63, #DISK_RESIZE_POWEROFF
#64 #DISK_RESIZE_UNDEPLOYED
#65 #HOTPLUG_NIC_POWEROFF
]
class OpenNebulaGuac
attr_reader :proxy_port
def initialize(config, logger, options = {})
opts={ :json_errors => true }.merge(options)
@lock_file = GUAC_LOCK_FILE
@guacd_pid_file = GUACD_PID_FILE
@options = opts
@logger = logger
end
def proxy(vm_resource, type_connection = "vnc")
# Check configurations and VM attributes
unless is_lockfile?
return error(400, "Guacamole server is not running")
end
if !is_running?
return error(400, "Guacamole server is not running")
end
if !is_guacd_running?
return error(400, "Guacamole proxy daemon is not running")
end
# Check configurations and VM attributes
if !GUAC_STATES.include?(vm_resource['LCM_STATE'])
return error(400, "Wrong state (#{vm_resource['LCM_STATE']}) to open a Guacamole session")
end
if !(["vnc", "rdp", "ssh"].include?(type_connection.downcase))
return error(400, "Type connection not supported by Guacamole")
end
# TODO (* : optional) ===============================
# =======================================================
# type : telnet
# hostname : vm_resource["TEMPLATE/NIC[1]/IP"]
# port* : 23 by default
# username* : vm_resource['TEMPLATE/CONTEXT/USERNAME']
# password* : vm_resource['TEMPLATE/CONTEXT/PASSWORD']
settings = case type_connection.downcase
when "vnc" then get_config_vnc(vm_resource)
when "rdp" then get_config_rdp(vm_resource)
when "ssh" then get_config_ssh(vm_resource)
else {:error => error(400, "Type connection not supported by Guacamole")}
end
return settings[:error] if settings.key?(:error)
data = encrypt_data({
"connection" => {
"type" => type_connection.downcase,
"settings" => {
"security" => "any",
"ignore-cert" => "true",
"enable-drive" => "true",
"enable-audio" => "true",
"create-drive-path" => "true",
}.merge!(settings)
}
})
[200, { :token => data }.to_json]
end
def status
if is_running?
STDOUT.puts "Guacamole server is running"
true
else
STDOUT.puts "Guacamole server is NOT running"
false
end
end
private
def error(code, msg)
if @options[:json_errors]
return [code,OpenNebula::Error.new(msg).to_json]
else
return [code,msg]
end
end
def is_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_guac_pid, :is_running?
def is_guacd_running?
if File.exist?(@guacd_pid_file)
pid=File.read(@guacd_pid_file).strip
if system("ps #{pid} 1> /dev/null")
return pid.to_i
end
end
false
end
alias_method :get_guacd_pid, :is_guacd_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(GUACAMOLE_LOG, "a")
$stderr.reopen(GUACAMOLE_LOG, "a")
$stdin.close
# Detach process from the parent
Process.setsid
exec(*command)
}
end
end
def get_config_vnc(vm_resource)
# If it is a vCenter VM
if vm_resource['USER_TEMPLATE/HYPERVISOR'] == "vcenter"
if vm_resource['MONITORING/VCENTER_ESX_HOST']
hostname = vm_resource['MONITORING/VCENTER_ESX_HOST']
else
return error(400,"Could not determine the vCenter ESX host where the VM is running.
Wait till the VCENTER_ESX_HOST attribute is retrieved once the host has been monitored")
end
else
hostname = vm_resource['/VM/HISTORY_RECORDS/HISTORY[last()]/HOSTNAME']
end
{ "hostname" => "localhost", "port" => "5900", "password" => nil }.merge({
"hostname" => hostname,
"port" => vm_resource['TEMPLATE/GRAPHICS/PORT'],
"password" => vm_resource['TEMPLATE/GRAPHICS/PASSWD']
})
end
def get_config_rdp(vm_resource)
hostname = vm_resource["TEMPLATE/NIC[RDP='YES'][1]/IP | TEMPLATE/NIC_ALIAS[RDP='YES'][1]/IP"]
return {
:error => error(400, "Wrong configuration. Cannot find a NIC with RDP")
} if hostname.nil?
{ "hostname" => "localhost", "port" => "3389", "username" => nil, "password" => nil }.merge({
"hostname" => hostname,
"port" => vm_resource['TEMPLATE/CONTEXT/RDP_PORT'],
"username" => vm_resource['TEMPLATE/CONTEXT/USERNAME'],
"password" => vm_resource['TEMPLATE/CONTEXT/PASSWORD']
})
end
def get_config_ssh(vm_resource)
hostname = vm_resource["TEMPLATE/NIC[SSH='YES'][1]/IP | TEMPLATE/NIC_ALIAS[SSH='YES'][1]/IP"]
return {
:error => error(400, "Wrong configuration. Cannot find a NIC with SSH")
} if hostname.nil?
{ "hostname" => "localhost", "port" => "22", "username" => nil, "password" => nil }.merge({
"hostname" => hostname,
"port" => vm_resource['TEMPLATE/CONTEXT/SSH_PORT'],
"username" => vm_resource['TEMPLATE/CONTEXT/USERNAME'],
"password" => vm_resource['TEMPLATE/CONTEXT/PASSWORD']
})
end
def encrypt_data(data)
iv = OpenSSL::Random.random_bytes(16)
key = 'LSIOGCKYLSIOGCKYLSIOGCKYLSIOGCKY' #OpenSSL::Random.random_bytes(32)
cipher = OpenSSL::Cipher::AES256.new(:CBC)
cipher.encrypt
cipher.key = key
cipher.iv = iv
crypted = cipher.update(data.to_json)
crypted << cipher.final
token = {
iv: Base64.encode64(iv).strip,
value: Base64.strict_encode64(crypted).strip
}
return Base64.strict_encode64(token.to_json).encode('utf-8').strip
end
end

View File

@ -1,196 +0,0 @@
#!/bin/bash
# -------------------------------------------------------------------------- #
# 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. #
#--------------------------------------------------------------------------- #
GUACD_BIN=/usr/local/sbin/guacd
if [ -z "$ONE_LOCATION" ]; then
GUAC_SERVER_DIR=/usr/lib/one/sunstone/guac
GUAC_LOCK_FILE=/var/lock/one/.guac.lock
GUAC_LOG=/var/log/one/guac.log
GUAC_LOG_ERROR=/var/log/one/guac.error
GUAC_PID=/var/run/one/guac.pid
GUACD_PID=/var/run/one/guacd.pid
SUNSTONE_CONF=/etc/one/sunstone-server.conf
else
GUAC_LOCK_FILE=$ONE_LOCATION/var/.guac.lock
GUAC_LOG=$ONE_LOCATION/var/guac.log
GUAC_LOG_ERROR=$ONE_LOCATION/var/guac.error
GUAC_PID=$ONE_LOCATION/var/guac.pid
GUACD_PID=$ONE_LOCATION/var/guacd.pid
SUNSTONE_CONF=$ONE_LOCATION/etc/sunstone-server.conf
fi
get_pid()
{
if [ -f "$1" ]; then
read PID < "$1"
# if pidfile contains PID and PID is valid
if [ -n "$PID" ] && ps "$PID" > /dev/null 2>&1; then
echo "$PID"
return 0
fi
fi
# pidfile/pid not found, or process is dead
return 1
}
start_guacd()
{
if [ ! -f "$GUACD_BIN" ]; then
echo "Cannot find $GUACD_BIN."
return 1
fi
PID=`get_pid $GUACD_PID`
if [ $? -eq 0 ]; then
echo "Guacamole proxy daemon already running"
return 1
fi
echo -n "Starting guacd: "
$GUACD_BIN -p "$GUACD_PID" > /dev/null 2>&1
case "$?" in
0)
echo "SUCCESS"
;;
*)
echo "FAIL"
;;
esac
}
stop_guacd()
{
echo -n "Stopping guacd: "
PID=`get_pid $GUACD_PID`
case "$?" in
0)
if kill -9 $PID > /dev/null 2>&1
then
echo "SUCCESS"
return 0
fi
echo "FAIL"
return 0
;;
*)
echo "SUCCESS (not running)"
return 0
;;
esac
}
setup()
{
if [ -f $GUAC_LOCK_FILE ]; then
PID=`get_pid $GUAC_PID`
if [ $? -eq 0 ]; then
echo -n "Guacamole Server is still running (PID:$PID). Please "
echo "try 'guac-server stop' first."
exit 1
fi
echo "Stale .lock detected. Erasing it."
rm $GUAC_LOCK_FILE
fi
}
start()
{
ENV_MODE=$(grep ^:env: $SUNSTONE_CONF|awk '{print $2}')
if [ "$ENV_MODE" = "dev" ]; then
GUAC_SERVER=$GUAC_SERVER_DIR/app.js
else
GUAC_SERVER=$GUAC_SERVER_DIR/dist/guac.js
fi
if [ ! -f "$GUAC_SERVER" ]; then
echo "Cannot find $GUAC_SERVER."
exit 1
fi
touch $GUAC_LOCK_FILE
# Start the guac-server daemon
GUAC_PORT=$(grep ^:guac_port: $SUNSTONE_CONF|awk '{print $2}')
GUACD_PORT=$(grep ^:guacd_port: $SUNSTONE_CONF|awk '{print $2}')
PORT="$GUAC_PORT" GUACD_PORT="$GUACD_PORT" node "$GUAC_SERVER" \
> $GUAC_LOG 2>$GUAC_LOG_ERROR &
LASTRC=$?
LASTPID=$!
if [ $LASTRC -ne 0 ]; then
echo "Error executing guac-server."
echo "Check $GUAC_LOG_ERROR and $GUAC_LOG for more information"
exit 1
else
echo $LASTPID > $GUAC_PID
fi
sleep 2
ps $LASTPID > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error executing guac-server."
echo "Check $GUAC_LOG_ERROR and $GUAC_LOG for more information"
exit 1
fi
echo "guac-server started"
}
#
# Function that stops the daemon/service
#
stop()
{
if [ ! -f $GUAC_PID ]; then
echo "Couldn't find guac-server process pid."
exit 1
fi
# Kill the guac-server daemon
kill -9 `cat $GUAC_PID` > /dev/null 2>&1
# Remove pid files
rm -f $GUAC_PID > /dev/null 2>&1
rm -f $GUAC_LOCK_FILE &> /dev/null
echo "guac-server stopped"
}
case "$1" in
start)
start_guacd
setup
start
;;
stop)
stop_guacd
stop
;;
*)
echo "Usage: guac-server {start|stop}" >&2
exit 3
;;
esac

View File

@ -158,6 +158,9 @@
:vnc_request_password: false
:allow_vnc_federation: no
# guacamole daemon port
:guacd_port: 4822
# Login Session Length in seconds, defaults to 1 hour.
#:session_expire_time: 3600
@ -271,6 +274,3 @@
# Number of tries when connecting to fireedge_endpoint
:max_waiting_tries: 5
:guac_port: 29877
:guacd_port: 4822

View File

@ -20,7 +20,7 @@ require 'OpenNebulaJSON'
include OpenNebulaJSON
require 'OpenNebulaVNC'
require 'OpenNebulaGuac'
require 'opennebula_guac'
require 'opennebula_vmrc'
require 'OpenNebulaAddons'
require 'OpenNebulaJSON/JSONUtils'

View File

@ -0,0 +1,362 @@
# -------------------------------------------------------------------------- #
# 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. #
#--------------------------------------------------------------------------- #
#
# This class provides support for launching and stopping a websockify proxy
#
require 'rubygems'
require 'json'
require 'opennebula'
require 'base64'
require 'openssl'
if !ONE_LOCATION
GUAC_LOCK_FILE = '/var/lock/one/.guac.lock'
GUACD_PID_FILE = '/var/run/one/guacd.pid'
else
GUAC_LOCK_FILE= ONE_LOCATION + '/var/.guac.lock'
GUACD_PID_FILE= ONE_LOCATION + '/var/guacd.pid'
end
GUAC_STATES = [
# 0, # LCM_INIT
# 1, # PROLOG
# 2, # BOOT
'3', # RUNNING
'4', # MIGRATE
# 5, # SAVE_STOP
# 6, # SAVE_SUSPEND
# 7, # SAVE_MIGRATE
# 8, # PROLOG_MIGRATE
# 9, # PROLOG_RESUME
# 10, # EPILOG_STOP
# 11, # EPILOG
'12', # SHUTDOWN
'13', # CANCEL
# 14, # FAILURE
# 15, # CLEANUP_RESUBMIT
'16', # UNKNOWN
'17', # HOTPLUG
'18', # SHUTDOWN_POWEROFF
# 19, # BOOT_UNKNOWN
# 20, # BOOT_POWEROFF
# 21, # BOOT_SUSPENDED
# 22, # BOOT_STOPPED
# 23, # CLEANUP_DELETE
'24', # HOTPLUG_SNAPSHOT
'25', # HOTPLUG_NIC
'26', # HOTPLUG_SAVEAS
'27', # HOTPLUG_SAVEAS_POWEROFF
'28', # HOTPLUG_SAVEAS_SUSPENDED
'29', # SHUTDOWN_UNDEPLOY
# 30, # EPILOG_UNDEPLOY
# 31, # PROLOG_UNDEPLOY
# 32, # BOOT_UNDEPLOY
# 33, # HOTPLUG_PROLOG_POWEROFF
# 34, # HOTPLUG_EPILOG_POWEROFF
# 35, # BOOT_MIGRATE
# 36, # BOOT_FAILURE
# 37, # BOOT_MIGRATE_FAILURE
# 38, # PROLOG_MIGRATE_FAILURE
# 39, # PROLOG_FAILURE
# 40, # EPILOG_FAILURE
# 41, # EPILOG_STOP_FAILURE
# 42, # EPILOG_UNDEPLOY_FAILURE
# 43, # PROLOG_MIGRATE_POWEROFF
# 44, # PROLOG_MIGRATE_POWEROFF_FAILURE
# 45, # PROLOG_MIGRATE_SUSPEND
# 46, # PROLOG_MIGRATE_SUSPEND_FAILURE
# 47, # BOOT_UNDEPLOY_FAILURE
# 48, # BOOT_STOPPED_FAILURE
# 49, # PROLOG_RESUME_FAILURE
# 50, # PROLOG_UNDEPLOY_FAILURE
# 51, # DISK_SNAPSHOT_POWEROFF
# 52, # DISK_SNAPSHOT_REVERT_POWEROFF
# 53, # DISK_SNAPSHOT_DELETE_POWEROFF
# 54, # DISK_SNAPSHOT_SUSPENDED
# 55, # DISK_SNAPSHOT_REVERT_SUSPENDED
# 56, # DISK_SNAPSHOT_DELETE_SUSPENDED
'57', # DISK_SNAPSHOT
'58', # DISK_SNAPSHOT_REVERT
# 59, # DISK_SNAPSHOT_DELETE
# 60, # PROLOG_MIGRATE_UNKNOWN
# 61, # PROLOG_MIGRATE_UNKNOWN_FAILURE
'62' # DISK_RESIZE
# 63, # DISK_RESIZE_POWEROFF
# 64, # DISK_RESIZE_UNDEPLOYED
# 65, #HOTPLUG_NIC_POWEROFF
]
# Class for Guacamole connection configuration
class OpenNebulaGuac
attr_reader :proxy_port
def initialize(logger, options = {})
opts={ :json_errors => true }.merge(options)
@lock_file = GUAC_LOCK_FILE
@guacd_pid_file = GUACD_PID_FILE
@options = opts
@logger = logger
end
def proxy(vm_resource, type_connection = 'vnc')
# Check configurations and VM attributes
unless lockfile?
return error(400, 'Guacamole server is not running')
end
unless running?
return error(400, 'Guacamole server is not running')
end
unless guacd_running?
return error(400, 'Guacamole proxy daemon is not running')
end
# Check configurations and VM attributes
if !GUAC_STATES.include?(vm_resource['LCM_STATE'])
error_message = "Wrong state (#{vm_resource['LCM_STATE']})
to open a Guacamole session"
return error(400, error_message)
end
unless %w[vnc rdp ssh].include?(type_connection.downcase)
return error(400, 'Type connection not supported by Guacamole')
end
# TODO, (* : optional) ================================
# =======================================================
# type : telnet
# hostname : vm_resource["TEMPLATE/NIC[1]/IP"]
# port* : 23 by default
# username* : vm_resource['TEMPLATE/CONTEXT/USERNAME']
# password* : vm_resource['TEMPLATE/CONTEXT/PASSWORD']
settings = nil
case type_connection.downcase
when 'vnc' then settings = get_config_vnc(vm_resource)
when 'rdp' then settings = get_config_rdp(vm_resource)
when 'ssh' then settings = get_config_ssh(vm_resource)
else {
:error => error(400, 'Type connection not supported by Guacamole')
}
end
return settings[:error] if settings.key?(:error)
data = encrypt_data(
{
'connection' => {
'type' => type_connection.downcase,
'settings' => {
'security' => 'any',
'ignore-cert' => 'true',
'enable-drive' => 'true',
'enable-audio' => 'true',
'create-drive-path' => 'true'
}.merge!(settings)
}
}
)
[200, { :token => data }.to_json]
end
def status
if running?
STDOUT.puts 'Guacamole server is running'
true
else
STDOUT.puts 'Guacamole server is NOT running'
false
end
end
private
def error(code, msg)
unless @options[:json_error]
return [code, msg]
end
[code, OpenNebula::Error.new(msg).to_json]
end
def 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 get_guac_pid running?
def guacd_running?
if File.exist?(@guacd_pid_file)
pid=File.read(@guacd_pid_file).strip
if system("ps #{pid} 1> /dev/null")
return pid.to_i
end
end
false
end
alias get_guacd_pid guacd_running?
def 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 do
command=args[0..-2]
# Close stdin and point out and err to log file
$stdout.reopen(GUACAMOLE_LOG, 'a')
$stderr.reopen(GUACAMOLE_LOG, 'a')
$stdin.close
# Detach process from the parent
Process.setsid
exec(*command)
end
end
end
def get_config_vnc(vm_resource)
# If it is a vCenter VM
if vm_resource['USER_TEMPLATE/HYPERVISOR'] == 'vcenter'
if vm_resource['MONITORING/VCENTER_ESX_HOST']
hostname = vm_resource['MONITORING/VCENTER_ESX_HOST']
else
error_message = 'Could not determine the vCenter ESX host where
the VM is running. Wait till the VCENTER_ESX_HOST attribute is
retrieved once the host has been monitored'
return error(400, error_message)
end
else
hostname = vm_resource[
'/VM/HISTORY_RECORDS/HISTORY[last()]/HOSTNAME'
]
end
{
'hostname' => 'localhost',
'port' => '5900',
'password' => nil
}.merge(
{
'hostname' => hostname,
'port' => vm_resource['TEMPLATE/GRAPHICS/PORT'],
'password' => vm_resource['TEMPLATE/GRAPHICS/PASSWD']
}
)
end
def get_config_rdp(vm_resource)
hostname = vm_resource["TEMPLATE/NIC[RDP='YES'][1]/IP"] ||
vm_resource["TEMPLATE/NIC_ALIAS[RDP='YES'][1]/IP"]
if hostname.nil?
error_message = 'Wrong configuration. Cannot find a NIC with RDP'
return { :error => error(400, error_message) }
end
{
'hostname' => 'localhost',
'port' => '3389',
'username' => nil,
'password' => nil
}.merge(
{
'hostname' => hostname,
'port' => vm_resource['TEMPLATE/CONTEXT/RDP_PORT'],
'username' => vm_resource['TEMPLATE/CONTEXT/USERNAME'],
'password' => vm_resource['TEMPLATE/CONTEXT/PASSWORD']
}
)
end
def get_config_ssh(vm_resource)
hostname = vm_resource["TEMPLATE/NIC[SSH='YES'][1]/IP"] ||
vm_resource["TEMPLATE/NIC_ALIAS[SSH='YES'][1]/IP"]
if hostname.nil?
error_message = 'Wrong configuration. Cannot find a NIC with SSH'
return { :error => error(400, error_message) }
end
{
'hostname' => 'localhost',
'port' => '22',
'username' => nil,
'password' => nil
}.merge(
{
'hostname' => hostname,
'port' => vm_resource['TEMPLATE/CONTEXT/SSH_PORT'],
'username' => vm_resource['TEMPLATE/CONTEXT/USERNAME'],
'password' => vm_resource['TEMPLATE/CONTEXT/PASSWORD']
}
)
end
def encrypt_data(data)
iv = OpenSSL::Random.random_bytes(16)
# OpenSSL::Random.random_bytes(32)
key = 'LSIOGCKYLSIOGCKYLSIOGCKYLSIOGCKY'
cipher = OpenSSL::Cipher.new('aes-256-cbc')
cipher.encrypt
cipher.key = key
cipher.iv = iv
crypted = cipher.update(data.to_json)
crypted << cipher.final
token = {
'iv' => Base64.encode64(iv).strip,
'value' => Base64.strict_encode64(crypted).strip
}
Base64.strict_encode64(token.to_json).encode('utf-8').strip
end
end

View File

@ -169,7 +169,6 @@ define(function(require) {
"scaleFactor": _config["view"]["features"]["instantiate_cpu_factor"],
"filterView": _config["view"]["filter-view"],
"doCountAnimation": _config["view"]["do_count_animation"],
"guacPort": _config["user_config"]["guac_port"],
"allTabs": function() {
return Object.keys(_config["view"]["tabs"]);

View File

@ -63,9 +63,13 @@ define(function(require) {
}
else setLoading(true);
var port = Config.guacPort || '29877';
var host = window.location.hostname || 'localhost';
var wsprotocol = (window.location.protocol == 'https:') ? 'wss:' : 'ws:';
var fireedge_protocol = Config.fireedgeEndpoint.split("//")[0];
var fireedge_host = Config.fireedgeEndpoint.split("//")[1].split(":")[0];
var fireedge_port = Config.fireedgeEndpoint.split("//")[1].split(":")[1];
var port = fireedge_port || '2616';
var host = fireedge_host || 'localhost';
var wsprotocol = (fireedge_protocol == 'https:') ? 'wss:' : 'ws:';
var tunnel = new Guacamole.WebSocketTunnel(wsprotocol + '//' + host + ':' + port + '/guacamole')
var guac = this._client = new Guacamole.Client(tunnel);

View File

@ -261,7 +261,7 @@ end
$vnc = OpenNebulaVNC.new($conf, logger)
#init Guacamole server
$guac = OpenNebulaGuac.new($conf, logger)
$guac = OpenNebulaGuac.new(logger)
#init VMRC server
$vmrc = OpenNebulaVMRC.new(logger)

View File

@ -41,7 +41,6 @@
'threshold_min' : '<%= $conf[:threshold_min] %>',
'threshold_low' : '<%= $conf[:threshold_low] %>',
'threshold_high' : '<%= $conf[:threshold_high] %>',
'guac_port' : '<%= $conf[:guac_port] %>',
},
'system_config' : {
'paginate': '<%= $conf[:paginate] %>',