diff --git a/install.sh b/install.sh index fb6452dba2..6a38084d7e 100755 --- a/install.sh +++ b/install.sh @@ -1075,7 +1075,8 @@ ETC_CLIENT_FILES="src/cli/etc/group.default" #----------------------------------------------------------------------------- SUNSTONE_FILES="src/sunstone/config.ru \ - src/sunstone/sunstone-server.rb" + src/sunstone/sunstone-server.rb \ + src/sunstone/OpenNebulaVNC.rb" SUNSTONE_BIN_FILES="src/sunstone/bin/sunstone-server" diff --git a/share/install_novnc.sh b/share/install_novnc.sh index 5dc90d6763..52dbf373ef 100755 --- a/share/install_novnc.sh +++ b/share/install_novnc.sh @@ -1,6 +1,7 @@ #!/bin/bash NOVNC_TMP=/tmp/one/novnc-$(date "+%Y%m%d%H%M%S") +PROXY_PATH=noVNC/utils/websockify if [ -z "$ONE_LOCATION" ]; then ONE_SHARE=/usr/share/one @@ -34,7 +35,7 @@ mv $ONE_SHARE/$dir $ONE_SHARE/noVNC mkdir -p $ONE_PUBLIC_SUNSTONE/vendor/noVNC mv $ONE_SHARE/noVNC/include/ $ONE_PUBLIC_SUNSTONE/vendor/noVNC/ -sed -i.bck "s%^\(:novnc_path: \).*$%\1$ONE_SHARE/noVNC%" $SUNSTONE_CONF +sed -i.bck "s%^\(:vnc_proxy_path: \).*$%\1$ONE_SHARE/$PROXY_PATH%" $SUNSTONE_CONF #Update file permissions chmod +x $ONE_SHARE/noVNC/utils/launch.sh diff --git a/src/sunstone/OpenNebulaVNC.rb b/src/sunstone/OpenNebulaVNC.rb new file mode 100644 index 0000000000..ecaac733b0 --- /dev/null +++ b/src/sunstone/OpenNebulaVNC.rb @@ -0,0 +1,90 @@ +# -------------------------------------------------------------------------- # +# Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) # +# # +# 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 file provides support for launching and stopping a websockify proxy + +require 'json' + +class OpenNebulaVNC + def initialize(config,opt={:json_errors => true}) + @proxy_path = config[:vnc_proxy_path] + @proxy_base_port = config[:vnc_proxy_base_port].to_i + @wss = config[:vnc_proxy_support_wss] + $stderr.puts "wss #{@wss}" + @enable_wss = (@wss == "yes") || (@wss == "only") + @cert = @enable_wss? config[:vnc_proxy_cert] : nil + @key = @enable_wss? config[:vnc_proxy_key] : nil + @options=opt + end + + def error(code, msg) + if @options[:json_errors] + return [code,OpenNebula::Error.new(msg).to_json] + else + return [code,msg] + end + end + + def start(vm_resource) + if vm_resource['LCM_STATE'] != "3" + return error(403,"VM is not running") + end + + if vm_resource['TEMPLATE/GRAPHICS/TYPE'] != "vnc" + return error(403,"VM has no VNC configured") + end + + # The VM host and its VNC port + host = vm_resource['/VM/HISTORY_RECORDS/HISTORY[last()]/HOSTNAME'] + vnc_port = vm_resource['TEMPLATE/GRAPHICS/PORT'] + # The port on which the proxy will listen + proxy_port = @proxy_base_port + vnc_port.to_i + + if !@proxy_path || @proxy_path.size == 0 + return error(403,"VNC proxy not configured") + end + + proxy_options = "" + + if @enable_wss + proxy_options += " --cert #{@cert}" + proxy_options += " --key #{@key}" if @key && @key.size > 0 + proxy_options += " --ssl-only" if @wss == "only" + end + + proxy_cmd = "#{@proxy_path} #{proxy_options} #{proxy_port} #{host}:#{vnc_port}" + + begin + $stderr.puts("Starting vnc proxy: #{proxy_cmd}") + pipe = IO.popen(proxy_cmd) + rescue Exception => e + error = Error.new(e.message) + return [500, error.to_json] + end + + vnc_pw = vm_resource['TEMPLATE/GRAPHICS/PASSWD'] + + info = {:pipe => pipe, :port => proxy_port, :password => vnc_pw} + return [200, info] + end + + #handle exceptions outside + def self.stop(pipe) + Process.kill('KILL',pipe.pid) + pipe.close + end +end diff --git a/src/sunstone/etc/sunstone-server.conf b/src/sunstone/etc/sunstone-server.conf index 1927bfb949..349fa484c1 100644 --- a/src/sunstone/etc/sunstone-server.conf +++ b/src/sunstone/etc/sunstone-server.conf @@ -16,8 +16,18 @@ :core_auth: cipher # VNC Configuration +# base_port: base_port + vnc_port of the VM is the port where the +# proxy will listen for VNC session connections to that VM. +# vnc_proxy_path: path to the websockets proxy (set by install_novnc.sh) +# support_wss: "no", "yes", "only". For yes and only, provide path to +# cert and key. Note value must be a quoted string. +# (key is only necessary if not included in cert). :vnc_proxy_base_port: 29876 -:novnc_path: +:vnc_proxy_path: +:vnc_proxy_support_wss: "no" +:vnc_proxy_cert: +:vnc_proxy_key: + # Default language setting :lang: en_US diff --git a/src/sunstone/models/SunstoneServer.rb b/src/sunstone/models/SunstoneServer.rb index a8113bcf65..359a24267e 100644 --- a/src/sunstone/models/SunstoneServer.rb +++ b/src/sunstone/models/SunstoneServer.rb @@ -18,6 +18,7 @@ require 'OpenNebulaJSON' include OpenNebulaJSON require 'acct/watch_client' +require 'OpenNebulaVNC' class SunstoneServer # FLAG that will filter the elements retrieved from the Pools @@ -147,35 +148,35 @@ class SunstoneServer end ############################################################################ - # + # Unused ############################################################################ - def get_configuration(user_id) - if user_id != "0" - return [401, ""] - end + # def get_configuration(user_id) + # if user_id != "0" + # return [401, ""] + # end - one_config = VAR_LOCATION + "/config" - config = Hash.new + # one_config = VAR_LOCATION + "/config" + # config = Hash.new - begin - cfg = File.read(one_config) - rescue Exception => e - error = Error.new("Error reading config: #{e.inspect}") - return [500, error.to_json] - end + # begin + # cfg = File.read(one_config) + # rescue Exception => e + # error = Error.new("Error reading config: #{e.inspect}") + # return [500, error.to_json] + # end - cfg.lines do |line| - m=line.match(/^([^=]+)=(.*)$/) + # cfg.lines do |line| + # m=line.match(/^([^=]+)=(.*)$/) - if m - name=m[1].strip.upcase - value=m[2].strip - config[name]=value - end - end + # if m + # name=m[1].strip.upcase + # value=m[2].strip + # config[name]=value + # end + # end - return [200, config.to_json] - end + # return [200, config.to_json] + # end ############################################################################ # @@ -211,50 +212,16 @@ class SunstoneServer return [404, resource.to_json] end - if resource['LCM_STATE'] != "3" - error = OpenNebula::Error.new("VM is not running") - return [403, error.to_json] - end - - if resource['TEMPLATE/GRAPHICS/TYPE'] != "vnc" - error = OpenNebula::Error.new("VM has no VNC configured") - return [403, error.to_json] - end - - # The VM host and its VNC port - host = resource['/VM/HISTORY_RECORDS/HISTORY[last()]/HOSTNAME'] - vnc_port = resource['TEMPLATE/GRAPHICS/PORT'] - # The noVNC proxy_port - proxy_port = config[:vnc_proxy_base_port].to_i + vnc_port.to_i - - begin - novnc_cmd = "#{config[:novnc_path]}/utils/wsproxy.py" - novnc_exec = "#{novnc_cmd} #{proxy_port} #{host}:#{vnc_port}" - $stderr.puts("Starting vnc proxy: #{novnc_exec}") - pipe = IO.popen(novnc_exec) - rescue Exception => e - error = Error.new(e.message) - return [500, error.to_json] - end - - vnc_pw = resource['TEMPLATE/GRAPHICS/PASSWD'] - - info = {:pipe => pipe, :port => proxy_port, :password => vnc_pw} - return [200, info] + vnc_proxy = OpenNebulaVNC.new(config) + return vnc_proxy.start(resource) end ############################################################################ # ############################################################################ - def stopvnc(id,pipe) - resource = retrieve_resource("vm", id) - if OpenNebula.is_error?(resource) - return [404, resource.to_json] - end - + def stopvnc(pipe) begin - Process.kill('KILL',pipe.pid) - pipe.close + OpenNebulaVNC.stop(pipe) rescue Exception => e error = Error.new(e.message) return [500, error.to_json] diff --git a/src/sunstone/public/js/plugins/config-tab.js b/src/sunstone/public/js/plugins/config-tab.js index 6f64a8bab4..126c509fcd 100644 --- a/src/sunstone/public/js/plugins/config-tab.js +++ b/src/sunstone/public/js/plugins/config-tab.js @@ -33,6 +33,12 @@ var config_tab_content = \ \ \ +