From 589e19142c51ab7af0bd2c2faa3ea09b7d5dca8c Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Mon, 30 Jan 2012 12:16:14 +0100 Subject: [PATCH 01/11] Feature #1069: Support secure-websocket-based VNC session in Sunstone. This commit adds support for using wss capabilities of websockify: * Add configuration option to Sunstone and saving/restore in user template support * Add new options to sunstone server configuration file * VNC session is started according to user setting * The code related to VNC proxy launch has been outsourced to OpenNebulaVNC.rb, so it can be mantained more easily and reused by, for example, SelfService. * Install novnc script has been corrected to point to "websockify" full path. Note: this commit changes vnc-related sunstone-server.conf keys and breaks vnc support in former versions of the configuration file. Update if necessary. (cherry picked from commit 00cf42e6b685a5ab26ca02d0eb142c311f56f6ee) --- install.sh | 3 +- share/install_novnc.sh | 3 +- src/sunstone/OpenNebulaVNC.rb | 90 ++++++++++++++++++++ src/sunstone/etc/sunstone-server.conf | 12 ++- src/sunstone/models/SunstoneServer.rb | 89 ++++++------------- src/sunstone/public/js/plugins/config-tab.js | 40 +++++++++ src/sunstone/public/js/plugins/vms-tab.js | 2 +- src/sunstone/sunstone-server.rb | 35 +++++++- 8 files changed, 205 insertions(+), 69 deletions(-) create mode 100644 src/sunstone/OpenNebulaVNC.rb diff --git a/install.sh b/install.sh index a9dee20015..ef321d1dd6 100755 --- a/install.sh +++ b/install.sh @@ -1077,7 +1077,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 = \ \ \ + \ + ' + tr("Secure websockets connection") + '\ + \ + \ + \ + \ \ \ \ @@ -48,6 +54,34 @@ var config_tab = { Sunstone.addMainTab('config_tab',config_tab); +function updateWss(){ + var user_info_req = { + data : { + id: uid, + }, + success: function(req,user_json) { + var template = user_json.USER.TEMPLATE; + var template_str=""; + template['VNC_WSS']= + $('#config_table #wss_checkbox').is(':checked') ? "yes" : "no"; + //convert json to ONE template format - simple conversion + $.each(template,function(key,value){ + template_str += (key + '=' + '"' + value + '"\n'); + }); + + var request = { + data: { + id: uid, + extra_param: template_str + }, + error: onError + }; + OpenNebula.User.update(request); + }, + }; + OpenNebula.User.show(user_info_req); +}; + $(document).ready(function(){ if (lang) $('table#config_table #lang_sel option[value="'+lang+'"]').attr('selected','selected'); @@ -55,4 +89,10 @@ $(document).ready(function(){ setLang($(this).val()); }); + $('table#config_table #wss_checkbox').change(updateWss); + + $.get('config/wss',function(response){ + if (response != "no") + $('table#config_table input#wss_checkbox').attr('checked','checked'); + }); }); \ No newline at end of file diff --git a/src/sunstone/public/js/plugins/vms-tab.js b/src/sunstone/public/js/plugins/vms-tab.js index fa69971dd6..cfb477c9c7 100644 --- a/src/sunstone/public/js/plugins/vms-tab.js +++ b/src/sunstone/public/js/plugins/vms-tab.js @@ -1227,7 +1227,7 @@ function setupVNC(){ function vncCallback(request,response){ rfb = new RFB({'target': $D('VNC_canvas'), - 'encrypt': false, + 'encrypt': $('#config_table #wss_checkbox').is(':checked'), 'true_color': true, 'local_cursor': true, 'shared': true, diff --git a/src/sunstone/sunstone-server.rb b/src/sunstone/sunstone-server.rb index 2ece360837..2e22b2aa3f 100755 --- a/src/sunstone/sunstone-server.rb +++ b/src/sunstone/sunstone-server.rb @@ -39,6 +39,7 @@ SUNSTONE_ROOT_DIR = File.dirname(__FILE__) $: << RUBY_LIB_LOCATION $: << RUBY_LIB_LOCATION+'/cloud' +$: << SUNSTONE_ROOT_DIR $: << SUNSTONE_ROOT_DIR+'/models' ############################################################################## @@ -115,12 +116,27 @@ helpers do session[:ip] = request.ip session[:remember] = params[:remember] + #User IU options initialization + #Load options either from user settings or default config. + # - LANG + # - WSS CONECTION + if user['TEMPLATE/LANG'] session[:lang] = user['TEMPLATE/LANG'] else session[:lang] = settings.config[:lang] end + if user['TEMPLATE/VNC_WSS'] + session[:wss] = user['TEMPLATE/VNC_WSS'] + else + session[:wss] = settings.config[:vnc_proxy_support_wss] + #limit to yes,no options + session[:wss] = (session[:wss] != "no" ? "yes" : "no") + end + + #end user options + if params[:remember] env['rack.session.options'][:expire_after] = 30*60*60*24 end @@ -212,8 +228,16 @@ end ############################################################################## # Config and Logs ############################################################################## -get '/config' do - @SunstoneServer.get_configuration(session[:user_id]) +#get '/config' do +# @SunstoneServer.get_configuration(session[:user_id]) +#end + +get '/config/:opt' do + case params[:opt] + when "lang" then session[:lang] + when "wss" then session[:wss] + else "unknown" + end end post '/config' do @@ -226,6 +250,7 @@ post '/config' do body.each do | key,value | case key when "lang" then session[:lang]=value + when "wss" then session[:wss]=value end end end @@ -301,7 +326,8 @@ post '/vm/:id/stopvnc' do return [403, OpenNebula::Error.new(msg).to_json] end - rc = @SunstoneServer.stopvnc(vm_id, vnc_hash[vm_id][:pipe]) + rc = @SunstoneServer.stopvnc(vnc_hash[vm_id][:pipe]) + if rc[0] == 200 session['vnc'].delete(vm_id) end @@ -327,7 +353,8 @@ post '/vm/:id/startvnc' do return [200, info.to_json] end - rc = @SunstoneServer.startvnc(vm_id, settings.config) + rc = @SunstoneServer.startvnc(vm_id,settings.config) + if rc[0] == 200 info = rc[1] session['vnc'][vm_id] = info.clone From cea817e9646cef4787157ef9bee7a72db5c88542 Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Mon, 13 Feb 2012 15:51:55 +0100 Subject: [PATCH 02/11] Feature #1069: Improvements for wss support and configuration in Sunstone. Allow non quoted yes | no values in configuration. Set wss configuration choice for the session so it stays if page reloaded (cherry picked from commit 6bb9cb74a22c0efbc7d51a949bea2d51c52a8dee) --- src/sunstone/OpenNebulaVNC.rb | 3 +-- src/sunstone/etc/sunstone-server.conf | 10 ++++++---- src/sunstone/public/js/plugins/config-tab.js | 1 + src/sunstone/sunstone-server.rb | 5 +++-- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/sunstone/OpenNebulaVNC.rb b/src/sunstone/OpenNebulaVNC.rb index ecaac733b0..e2e3ac3fde 100644 --- a/src/sunstone/OpenNebulaVNC.rb +++ b/src/sunstone/OpenNebulaVNC.rb @@ -24,8 +24,7 @@ class OpenNebulaVNC @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") + @enable_wss = (@wss == "yes") || (@wss == "only") || (@wss == true) @cert = @enable_wss? config[:vnc_proxy_cert] : nil @key = @enable_wss? config[:vnc_proxy_key] : nil @options=opt diff --git a/src/sunstone/etc/sunstone-server.conf b/src/sunstone/etc/sunstone-server.conf index 349fa484c1..bcc7e8225f 100644 --- a/src/sunstone/etc/sunstone-server.conf +++ b/src/sunstone/etc/sunstone-server.conf @@ -19,12 +19,14 @@ # 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). +# support_wss: no | yes | only. For yes and only, provide path to +# cert and key. "yes" means both ws and wss connections will be +# supported. +# vnc_proxy_cert: Certificate to encrypt wss connections. +# vnc_proxy_key: Key for wss connections. Only necessary if not included in cert. :vnc_proxy_base_port: 29876 :vnc_proxy_path: -:vnc_proxy_support_wss: "no" +:vnc_proxy_support_wss: no :vnc_proxy_cert: :vnc_proxy_key: diff --git a/src/sunstone/public/js/plugins/config-tab.js b/src/sunstone/public/js/plugins/config-tab.js index 126c509fcd..f342e91665 100644 --- a/src/sunstone/public/js/plugins/config-tab.js +++ b/src/sunstone/public/js/plugins/config-tab.js @@ -80,6 +80,7 @@ function updateWss(){ }, }; OpenNebula.User.show(user_info_req); + $.post('config',JSON.stringify({wss : ($('#config_table #wss_checkbox').is(':checked') ? "yes" : "no")})); }; $(document).ready(function(){ diff --git a/src/sunstone/sunstone-server.rb b/src/sunstone/sunstone-server.rb index 2e22b2aa3f..bb9bdeba03 100755 --- a/src/sunstone/sunstone-server.rb +++ b/src/sunstone/sunstone-server.rb @@ -130,9 +130,10 @@ helpers do if user['TEMPLATE/VNC_WSS'] session[:wss] = user['TEMPLATE/VNC_WSS'] else - session[:wss] = settings.config[:vnc_proxy_support_wss] + wss = settings.config[:vnc_proxy_support_wss] #limit to yes,no options - session[:wss] = (session[:wss] != "no" ? "yes" : "no") + session[:wss] = (wss == true || wss == "yes" || wss == "only" ? + "yes" : "no") end #end user options From 9f66d8b2e2064af69c84b1ae64608b7aa3a5df28 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Mon, 13 Feb 2012 17:50:49 +0100 Subject: [PATCH 03/11] feature #1069: Minor changes in OpenNebulaVNC class. Return user configuration in JSON --- src/sunstone/OpenNebulaVNC.rb | 74 ++++++++++++++++----------- src/sunstone/models/SunstoneServer.rb | 46 ++--------------- src/sunstone/sunstone-server.rb | 24 ++++----- 3 files changed, 59 insertions(+), 85 deletions(-) diff --git a/src/sunstone/OpenNebulaVNC.rb b/src/sunstone/OpenNebulaVNC.rb index e2e3ac3fde..ef628662f2 100644 --- a/src/sunstone/OpenNebulaVNC.rb +++ b/src/sunstone/OpenNebulaVNC.rb @@ -14,31 +14,38 @@ # limitations under the License. # #--------------------------------------------------------------------------- # - -#This file provides support for launching and stopping a websockify proxy - require 'json' +require 'OpenNebula' +# +# This class provides support for launching and stopping a websockify proxy +# class OpenNebulaVNC - def initialize(config,opt={:json_errors => true}) - @proxy_path = config[:vnc_proxy_path] + 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] - @enable_wss = (@wss == "yes") || (@wss == "only") || (@wss == true) - @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] + if (@wss == "yes") || (@wss == "only") || (@wss == true) + @enable_wss = true + @cert = config[:vnc_proxy_cert] + @key = config[:vnc_proxy_key] else - return [code,msg] + @enable_wss = false end + + @options = opt end + # Start a VNC proxy def start(vm_resource) + # Check configurations and VM attributes + + if @proxy_path == nil || @proxy_path.empty? + return error(403,"VNC proxy not configured") + end + if vm_resource['LCM_STATE'] != "3" return error(403,"VM is not running") end @@ -47,43 +54,50 @@ class OpenNebulaVNC 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'] + # Proxy data + 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_port = @proxy_base_port + vnc_port.to_i 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" + 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}" + cmd ="#{@proxy_path} #{proxy_options} #{proxy_port} #{host}:#{vnc_port}" begin $stderr.puts("Starting vnc proxy: #{proxy_cmd}") - pipe = IO.popen(proxy_cmd) + pipe = IO.popen(cmd) rescue Exception => e - error = Error.new(e.message) - return [500, error.to_json] + return [500, OpenNebula::Error.new(e.message).to_json] end vnc_pw = vm_resource['TEMPLATE/GRAPHICS/PASSWD'] + info = {:pipe => pipe, :port => proxy_port, :password => vnc_pw} - info = {:pipe => pipe, :port => proxy_port, :password => vnc_pw} return [200, info] end - #handle exceptions outside + # Stop a VNC proxy handle exceptions outside def self.stop(pipe) Process.kill('KILL',pipe.pid) pipe.close end + + private + + def error(code, msg) + if @options[:json_errors] + return [code,OpenNebula::Error.new(msg).to_json] + else + return [code,msg] + end + end + + end diff --git a/src/sunstone/models/SunstoneServer.rb b/src/sunstone/models/SunstoneServer.rb index 359a24267e..0c21f8440d 100644 --- a/src/sunstone/models/SunstoneServer.rb +++ b/src/sunstone/models/SunstoneServer.rb @@ -147,37 +147,6 @@ class SunstoneServer end end - ############################################################################ - # Unused - ############################################################################ - # def get_configuration(user_id) - # if user_id != "0" - # return [401, ""] - # end - - # 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 - - # cfg.lines do |line| - # m=line.match(/^([^=]+)=(.*)$/) - - # if m - # name=m[1].strip.upcase - # value=m[2].strip - # config[name]=value - # end - # end - - # return [200, config.to_json] - # end - ############################################################################ # ############################################################################ @@ -202,7 +171,6 @@ class SunstoneServer end end - ######################################################################## # VNC ######################################################################## @@ -233,7 +201,6 @@ class SunstoneServer ############################################################################ # ############################################################################ - def get_monitoring(id, resource, monitor_resources, gid) watch_client = case resource when "vm","VM" @@ -262,18 +229,11 @@ class SunstoneServer return [200, rc.to_json] end - ############################################################################ - # - ############################################################################ - - ############################################################################ - # - ############################################################################ - - - private + ############################################################################ + # + ############################################################################ def retrieve_resource(kind, id) resource = case kind when "group" then GroupJSON.new_with_id(id, @client) diff --git a/src/sunstone/sunstone-server.rb b/src/sunstone/sunstone-server.rb index bb9bdeba03..62081e24f2 100755 --- a/src/sunstone/sunstone-server.rb +++ b/src/sunstone/sunstone-server.rb @@ -227,18 +227,18 @@ post '/logout' do end ############################################################################## -# Config and Logs +# User configuration and VM logs ############################################################################## -#get '/config' do -# @SunstoneServer.get_configuration(session[:user_id]) -#end -get '/config/:opt' do - case params[:opt] - when "lang" then session[:lang] - when "wss" then session[:wss] - else "unknown" - end +get '/config' do + uconf = { + :user_config => { + :lang => session[:lang] + :wss => session[:wss] + } + } + + [200, uconf.json] end post '/config' do @@ -250,8 +250,8 @@ post '/config' do body.each do | key,value | case key - when "lang" then session[:lang]=value - when "wss" then session[:wss]=value + when "lang" then session[:lang]= value + when "wss" then session[:wss] = value end end end From 0449177b853c5d9f087ae99a22a775e5ec50ae32 Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Mon, 13 Feb 2012 15:55:11 +0100 Subject: [PATCH 04/11] Feature #1076: Add VNC support in SelfService. When enabled in the occi server configuration file, UI users will be able to click the VNC icon that appears in the VM information. Then the websockets proxy will be set up, provided that the machine has been configured with the appropiate GRAPHICS section etc. This must be done in the OCCI templates, and cannot be done by the UI user. Wss sessions can be configured in the occi server configuration file. Unlike Sunstone, here they are transparent to the user and whenever they are enabled VNC sessions will be launched using wss:// automaticly. As such, it is not up to the user to choose the type of connection, and it fully depends on the server configuration. Additionally the install_novnc.sh script has been updated and improved. The install.sh has been updated too. (cherry picked from commit 4ccaf9704a5d415e4979bbf53dce263d2c1e7cdb) --- install.sh | 3 +- share/install_novnc.sh | 31 ++++++--- src/cloud/occi/etc/occi-server.conf | 23 ++++++- src/cloud/occi/lib/OCCIServer.rb | 32 ++++++++- src/cloud/occi/lib/occi-server.rb | 69 ++++++++++++++++++- src/cloud/occi/lib/ui/public/js/locale.js | 2 +- src/cloud/occi/lib/ui/public/js/occi.js | 9 ++- .../occi/lib/ui/public/js/plugins/compute.js | 42 ++++++++--- .../lib/ui/public/js/plugins/configuration.js | 25 +++++-- 9 files changed, 205 insertions(+), 31 deletions(-) diff --git a/install.sh b/install.sh index ef321d1dd6..b0d21b42ff 100755 --- a/install.sh +++ b/install.sh @@ -1013,7 +1013,8 @@ OCCI_LIB_FILES="src/cloud/occi/lib/OCCIServer.rb \ src/cloud/occi/lib/UserOCCI.rb \ src/cloud/occi/lib/UserPoolOCCI.rb \ src/cloud/occi/lib/ImageOCCI.rb \ - src/cloud/occi/lib/ImagePoolOCCI.rb" + src/cloud/occi/lib/ImagePoolOCCI.rb \ + src/sunstone/OpenNebulaVNC.rb" OCCI_LIB_CLIENT_FILES="src/cloud/occi/lib/OCCIClient.rb" diff --git a/share/install_novnc.sh b/share/install_novnc.sh index 52dbf373ef..861fe78315 100755 --- a/share/install_novnc.sh +++ b/share/install_novnc.sh @@ -7,35 +7,50 @@ if [ -z "$ONE_LOCATION" ]; then ONE_SHARE=/usr/share/one ONE_PUBLIC_SUNSTONE=/usr/lib/one/sunstone/public SUNSTONE_CONF=/etc/one/sunstone-server.conf + ONE_PUBLIC_SELFSERVICE=/usr/lib/one/ruby/cloud/occi/ui/public + SELFSERVICE_CONF=/etc/one/occi-server.conf else ONE_SHARE=$ONE_LOCATION/share ONE_PUBLIC_SUNSTONE=$ONE_LOCATION/lib/sunstone/public SUNSTONE_CONF=$ONE_LOCATION/etc/sunstone-server.conf + ONE_PUBLIC_SELFSERVICE=$ONE_LOCATION/lib/ruby/cloud/occi/ui/public + SELFSERVICE_CONF=$ONE_LOCATION/etc/occi-server.conf fi +echo "Downloading noVNC latest version..." mkdir -p $NOVNC_TMP -wget -P $NOVNC_TMP --no-check-certificate http://github.com/kanaka/noVNC/tarball/master - +cd $NOVNC_TMP +curl -O -# -L http://github.com/kanaka/noVNC/tarball/master if [ $? -ne 0 ]; then - echo "Error downloading noVNC" + echo "\nError downloading noVNC" exit 1 fi +echo "Extracting files to temporary folder..." tar=`ls -rt $NOVNC_TMP|tail -n1` -tar -C $ONE_SHARE -mxvzf $NOVNC_TMP/$tar +tar -C $ONE_SHARE -mxzf $NOVNC_TMP/$tar if [ $? -ne 0 ]; then echo "Error untaring noVNC" exit 1 fi +echo "Moving files to OpenNebula $ONE_SHARE folder..." +rm -rf $ONE_SHARE/noVNC dir=`ls -rt $ONE_SHARE|tail -n1` mv $ONE_SHARE/$dir $ONE_SHARE/noVNC +echo "Installing Sunstone client libraries in $ONE_PUBLIC_SUNSTONE..." mkdir -p $ONE_PUBLIC_SUNSTONE/vendor/noVNC -mv $ONE_SHARE/noVNC/include/ $ONE_PUBLIC_SUNSTONE/vendor/noVNC/ +cp -r $ONE_SHARE/noVNC/include/ $ONE_PUBLIC_SUNSTONE/vendor/noVNC/ -sed -i.bck "s%^\(:vnc_proxy_path: \).*$%\1$ONE_SHARE/$PROXY_PATH%" $SUNSTONE_CONF +echo "Installing SelfService client libraries in $ONE_PUBLIC_SELFSERVICE..." +mkdir -p $ONE_PUBLIC_SELFSERVICE/vendor/noVNC +cp -r $ONE_SHARE/noVNC/include/ $ONE_PUBLIC_SELFSERVICE/vendor/noVNC/ -#Update file permissions -chmod +x $ONE_SHARE/noVNC/utils/launch.sh +echo "Backing up and updating $SUNSTONE_CONF with new VNC proxy path..." +sed -i.bck "s%^\(:vnc_proxy_path:\).*$%\1 $ONE_SHARE/$PROXY_PATH%" $SUNSTONE_CONF +echo "Backing up and updating $SELFSERVICE_CONF with new VNC proxy path..." +sed -i.bck "s%^\(:vnc_proxy_path:\).*$%\1 $ONE_SHARE/$PROXY_PATH%" $SELFSERVICE_CONF + +echo "Installation successful" \ No newline at end of file diff --git a/src/cloud/occi/etc/occi-server.conf b/src/cloud/occi/etc/occi-server.conf index 0084890209..90ea4df134 100644 --- a/src/cloud/occi/etc/occi-server.conf +++ b/src/cloud/occi/etc/occi-server.conf @@ -52,5 +52,26 @@ :cpu: 8 :memory: 8192 -# Default language setting for Self-Service UI + +############################################################# +### SelfService UI Settings +############################################################# + +# Default language setting :lang: en_US + +# VNC Configuration +# vnc_enable: yes | no. Allow users to launch vnc sessions. +# 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. If yes or only provide path to cert and key. +# "yes" means the proxy will accept both ws and wss connections. +# vnc_proxy_cert: Certificate to encrypt wss connections. +# vnc_proxy_key: Key for wss connections. Only necessary if not included in cert. +:vnc_enable: no +:vnc_proxy_base_port: 33876 +:vnc_proxy_path: +:vnc_proxy_support_wss: no +:vnc_proxy_cert: +:vnc_proxy_key: diff --git a/src/cloud/occi/lib/OCCIServer.rb b/src/cloud/occi/lib/OCCIServer.rb index 8a4f66cf33..12035fe18a 100755 --- a/src/cloud/occi/lib/OCCIServer.rb +++ b/src/cloud/occi/lib/OCCIServer.rb @@ -30,6 +30,8 @@ require 'ImagePoolOCCI' require 'UserOCCI' require 'UserPoolOCCI' +require 'OpenNebulaVNC' + require 'pp' @@ -236,7 +238,6 @@ class OCCIServer < CloudServer return to_occi_xml(vm, :status=>200) end - # Deletes a COMPUTE resource # request:: _Hash_ hash containing the data of the request # [return] _String_,_Integer_ Delete confirmation msg or error, @@ -505,4 +506,33 @@ class OCCIServer < CloudServer return to_occi_xml(user, :status=>200) end + + ############################################################################ + # VNC Methods + ############################################################################ + + def startvnc(id,config) + vm = VirtualMachineOCCI.new( + VirtualMachine.build_xml(id), + @client) + + rc = vm.info + if OpenNebula.is_error?(rc) + error = "Error starting VNC session, " + error += "could not retrieve Virtual Machine" + return [404,error] + end + + vnc_proxy = OpenNebulaVNC.new(config,{:json_errors => false}) + return vnc_proxy.start(vm) + end + + def stopvnc(pipe) + begin + OpenNebulaVNC.stop(pipe) + rescue Exception => e + return [500, e.message] + end + return [200,nil] + end end diff --git a/src/cloud/occi/lib/occi-server.rb b/src/cloud/occi/lib/occi-server.rb index 470ec9e19a..b64016525d 100755 --- a/src/cloud/occi/lib/occi-server.rb +++ b/src/cloud/occi/lib/occi-server.rb @@ -309,7 +309,19 @@ end ## UI ############################################## -post '/config' do +get '/ui/config/:opt' do + case params[:opt] + when "lang" then session[:lang] + when "wss" + wss = settings.config[:vnc_proxy_support_wss] + wss = (wss == true || wss == "yes" || wss == "only" ? "yes" : "no") + return wss + when "vnc" then settings.config[:vnc_enable] ? "yes" : "no" + else [404, "Unknown configuration option"] + end +end + +post '/ui/config' do begin body = JSON.parse(request.body.read) rescue @@ -321,6 +333,7 @@ post '/config' do when "lang" then session[:lang]=value end end + return 200 end get '/ui/login' do @@ -355,3 +368,57 @@ post '/ui/upload' do result,rc = @occi_server.post_storage(request) treat_response(result,rc) end + +post '/ui/startvnc/:id' do + if !settings.config[:vnc_enable] + return [403, "VNC sessions are disabled"] + end + + vm_id = params[:id] + + vnc_hash = session['vnc'] + + if !vnc_hash + session['vnc']= {} + elsif vnc_hash[vm_id] + #return existing information + info = vnc_hash[vm_id].clone + info.delete(:pipe) + + return [200, info.to_json] + end + + rc = @occi_server.startvnc(vm_id, settings.config) + + if rc[0] == 200 + info = rc[1] + session['vnc'][vm_id] = info.clone + info.delete(:pipe) + + [200, info.to_json] + else + rc + end +end + +post '/ui/stopvnc/:id' do + if !settings.config[:vnc_enable] + return [403, "VNC sessions are disabled"] + end + + vm_id = params[:id] + vnc_hash = session['vnc'] + + if !vnc_hash || !vnc_hash[vm_id] + msg = "It seems there is no VNC proxy running for this machine" + return [403, msg] + end + + rc = @occi_server.stopvnc(vnc_hash[vm_id][:pipe]) + + if rc[0] == 200 + session['vnc'].delete(vm_id) + end + + rc +end diff --git a/src/cloud/occi/lib/ui/public/js/locale.js b/src/cloud/occi/lib/ui/public/js/locale.js index be816c7239..792772954f 100644 --- a/src/cloud/occi/lib/ui/public/js/locale.js +++ b/src/cloud/occi/lib/ui/public/js/locale.js @@ -45,7 +45,7 @@ function setLang(lang_str){ if (('localStorage' in window) && (window['localStorage'] !== null)){ localStorage['lang']=lang_str; }; - $.post('config',JSON.stringify({lang:lang_str}),function(){window.location.href = "./ui"}); + $.post('ui/config',JSON.stringify({lang:lang_str}),function(){window.location.href = "./ui"}); }; $(document).ready(function(){ diff --git a/src/cloud/occi/lib/ui/public/js/occi.js b/src/cloud/occi/lib/ui/public/js/occi.js index 004938dc67..569a75e527 100644 --- a/src/cloud/occi/lib/ui/public/js/occi.js +++ b/src/cloud/occi/lib/ui/public/js/occi.js @@ -413,7 +413,7 @@ var OCCI = { params.data.body = ''; OCCI.Action.update(params,OCCI.VM.resource,"saveas"); }, -/* "vnc" : function(params,startstop){ + "vnc" : function(params,startstop){ var callback = params.success; var callback_error = params.error; var id = params.data.id; @@ -423,7 +423,7 @@ var OCCI = { var action = OCCI.Helper.action(method); var request = OCCI.Helper.request(resource,method, id); $.ajax({ - url: "vm/" + id + "/" + method, + url: "ui/" + method + "/" + id, type: "POST", dataType: "json", success: function(response){ @@ -440,13 +440,16 @@ var OCCI = { }, "stopvnc" : function(params){ OCCI.VM.vnc(params,"stopvnc"); + }, +/* "monitor" : function(params){ OCCI.Action.monitor(params,OCCI.VM.resource,false); }, "monitor_all" : function(params){ OCCI.Action.monitor(params,OCCI.VM.resource,true); - }*/ + } +*/ }, "Image": { diff --git a/src/cloud/occi/lib/ui/public/js/plugins/compute.js b/src/cloud/occi/lib/ui/public/js/plugins/compute.js index 993faf93ab..5613a1b3a2 100644 --- a/src/cloud/occi/lib/ui/public/js/plugins/compute.js +++ b/src/cloud/occi/lib/ui/public/js/plugins/compute.js @@ -15,16 +15,19 @@ /* -------------------------------------------------------------------------- */ /*Virtual Machines tab plugin*/ -//var INCLUDE_URI = "vendor/noVNC/include/"; +var INCLUDE_URI = "vendor/noVNC/include/"; //var VM_HISTORY_LENGTH = 40; -/* + function loadVNC(){ var script = ''; document.write(script); } loadVNC(); +var vnc_enable=false; +var use_wss=false; +/* var vm_graphs = [ { title : tr("CPU"), monitor_resources : "cpu_usage", @@ -264,7 +267,6 @@ var vm_actions = { error: onError }, - /* "VM.startvnc" : { type: "single", call: OCCI.VM.startvnc, @@ -280,6 +282,7 @@ var vm_actions = { notify: true }, +/* "VM.monitor" : { type: "monitor", call : OCCI.VM.monitor, @@ -540,6 +543,10 @@ function updateVMInfo(request,vm){ '+tr("Memory")+'\ '+vm_info.MEMORY+'\ \ + \ + '+tr("Launch VNC session")+'\ + '+vncIcon(vm_info)+'\ + \ \ \
\ @@ -940,7 +947,7 @@ function setVMAutorefresh(){ },INTERVAL+someTime()); } -/* + function updateVNCState(rfb, state, oldstate, msg) { var s, sb, cad, klass; s = $D('VNC_status'); @@ -1016,7 +1023,7 @@ function setupVNC(){ Sunstone.runAction("VM.stopvnc",id); }); - $('.vnc',main_tabs_context).live("click",function(){ + $('.vnc').live("click",function(){ //Which VM is it? var id = $(this).attr('vm_id'); //Set attribute to dialog @@ -1029,7 +1036,7 @@ function setupVNC(){ function vncCallback(request,response){ rfb = new RFB({'target': $D('VNC_canvas'), - 'encrypt': false, + 'encrypt': use_wss, 'true_color': true, 'local_cursor': true, 'shared': true, @@ -1049,6 +1056,20 @@ function vncCallback(request,response){ } +function vncIcon(vm){ + var gr_icon; + if (vnc_enable){ + gr_icon = ''; + gr_icon += '\"'+tr("Open'; + } + else { + gr_icon = '\"'+tr("VNC'; + } + return gr_icon; +} + +/* + function vncIcon(vm){ var graphics = vm.TEMPLATE.GRAPHICS; var state = vm.STATE; @@ -1063,6 +1084,9 @@ function vncIcon(vm){ return gr_icon; } +*/ + +/* function vmMonitorError(req,error_json){ var message = error_json.error.message; var info = req.request.data[0].monitor; @@ -1070,9 +1094,9 @@ function vmMonitorError(req,error_json){ var id_suffix = labels.replace(/,/g,'_'); var id = '#vm_monitor_'+id_suffix; $('#vm_monitoring_tab '+id).html('
'+message+'
'); -} +}*/ + -*/ // At this point the DOM is ready and the sunstone.js ready() has been run. $(document).ready(function(){ @@ -1102,7 +1126,7 @@ $(document).ready(function(){ //setupCreateVMDialog(); setupSaveasDialog(); setVMAutorefresh(); - //setupVNC(); + setupVNC(); initCheckAllBoxes(dataTable_vMachines); tableCheckboxesListener(dataTable_vMachines); diff --git a/src/cloud/occi/lib/ui/public/js/plugins/configuration.js b/src/cloud/occi/lib/ui/public/js/plugins/configuration.js index c92844ac1e..de32d3e084 100644 --- a/src/cloud/occi/lib/ui/public/js/plugins/configuration.js +++ b/src/cloud/occi/lib/ui/public/js/plugins/configuration.js @@ -49,16 +49,29 @@ var config_tab = { Sunstone.addMainTab('config_tab',config_tab); $(document).ready(function(){ - if (lang) - $('table#config_table #lang_sel option[value="'+lang+'"]').attr('selected','selected'); - $('table#config_table #lang_sel').change(function(){ - setLang($(this).val()); - }); - $('#li_config_tab').click(function(){ hideDialog(); }); + //Set lang to the right value + if (lang) + $('table#config_table #lang_sel option[value="'+lang+'"]').attr('selected','selected'); + + //Listen to changes in language + $('table#config_table #lang_sel').change(function(){ + setLang($(this).val()); + }); + + //Vendor customization, change small logo $('div#logo img').attr('src',logo_small); + $.get('ui/config/vnc',function(response){ + if (response == "true" || response == "yes") + vnc_enable=true; //defined in compute.js + }); + + $.get('ui/config/wss', function(response){ + if (response == "true" || response == "yes") + use_wss=true; //defined in compute.js + }); }); \ No newline at end of file From 8ecc77cd78652d9d7c4215e8811932c3acf9e17e Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Mon, 13 Feb 2012 18:23:05 +0100 Subject: [PATCH 05/11] feature #1076: UI configuration returned as XML --- src/cloud/occi/etc/occi-server.conf | 4 +-- src/cloud/occi/lib/OCCIServer.rb | 13 ++++----- src/cloud/occi/lib/occi-server.rb | 44 +++++++++++++++-------------- 3 files changed, 31 insertions(+), 30 deletions(-) diff --git a/src/cloud/occi/etc/occi-server.conf b/src/cloud/occi/etc/occi-server.conf index 90ea4df134..7d42afbf3d 100644 --- a/src/cloud/occi/etc/occi-server.conf +++ b/src/cloud/occi/etc/occi-server.conf @@ -52,9 +52,8 @@ :cpu: 8 :memory: 8192 - ############################################################# -### SelfService UI Settings +# OCCI UI Settings (SelfService) ############################################################# # Default language setting @@ -70,6 +69,7 @@ # vnc_proxy_cert: Certificate to encrypt wss connections. # vnc_proxy_key: Key for wss connections. Only necessary if not included in cert. :vnc_enable: no + :vnc_proxy_base_port: 33876 :vnc_proxy_path: :vnc_proxy_support_wss: no diff --git a/src/cloud/occi/lib/OCCIServer.rb b/src/cloud/occi/lib/OCCIServer.rb index 12035fe18a..f762fe1fbc 100755 --- a/src/cloud/occi/lib/OCCIServer.rb +++ b/src/cloud/occi/lib/OCCIServer.rb @@ -512,15 +512,13 @@ class OCCIServer < CloudServer ############################################################################ def startvnc(id,config) - vm = VirtualMachineOCCI.new( - VirtualMachine.build_xml(id), - @client) - + vm = VirtualMachineOCCI.new(VirtualMachine.build_xml(id), @client) rc = vm.info + if OpenNebula.is_error?(rc) - error = "Error starting VNC session, " - error += "could not retrieve Virtual Machine" - return [404,error] + error = "Error starting VNC session, " + error << "could not retrieve Virtual Machine" + return [404, error] end vnc_proxy = OpenNebulaVNC.new(config,{:json_errors => false}) @@ -533,6 +531,7 @@ class OCCIServer < CloudServer rescue Exception => e return [500, e.message] end + return [200,nil] end end diff --git a/src/cloud/occi/lib/occi-server.rb b/src/cloud/occi/lib/occi-server.rb index b64016525d..047fe55cad 100755 --- a/src/cloud/occi/lib/occi-server.rb +++ b/src/cloud/occi/lib/occi-server.rb @@ -306,19 +306,22 @@ get '/user/:id' do end ############################################## -## UI +## OCCI UI (Self-Service) ############################################## -get '/ui/config/:opt' do - case params[:opt] - when "lang" then session[:lang] - when "wss" - wss = settings.config[:vnc_proxy_support_wss] - wss = (wss == true || wss == "yes" || wss == "only" ? "yes" : "no") - return wss - when "vnc" then settings.config[:vnc_enable] ? "yes" : "no" - else [404, "Unknown configuration option"] - end +get '/ui/config' do + wss = settings.config[:vnc_proxy_support_wss] + wss = (wss == true || wss == "yes" || wss == "only" ? "yes" : "no") + + vnc = settings.config[:vnc_enable] ? "yes" : "no" + + config = "" + config << " #{session[:lang]}" + congig << " #{wss}" + congig << " #{vnc}" + config << "" + + return [200, config] end post '/ui/config' do @@ -333,6 +336,7 @@ post '/ui/config' do when "lang" then session[:lang]=value end end + return 200 end @@ -374,12 +378,11 @@ post '/ui/startvnc/:id' do return [403, "VNC sessions are disabled"] end - vm_id = params[:id] - + vm_id = params[:id] vnc_hash = session['vnc'] if !vnc_hash - session['vnc']= {} + session['vnc'] = {} elsif vnc_hash[vm_id] #return existing information info = vnc_hash[vm_id].clone @@ -395,10 +398,10 @@ post '/ui/startvnc/:id' do session['vnc'][vm_id] = info.clone info.delete(:pipe) - [200, info.to_json] - else - rc + rc = [200, info.to_json] end + + return rc end post '/ui/stopvnc/:id' do @@ -406,12 +409,11 @@ post '/ui/stopvnc/:id' do return [403, "VNC sessions are disabled"] end - vm_id = params[:id] + vm_id = params[:id] vnc_hash = session['vnc'] if !vnc_hash || !vnc_hash[vm_id] - msg = "It seems there is no VNC proxy running for this machine" - return [403, msg] + return [403, "It seems there is no VNC proxy running for this machine"] end rc = @occi_server.stopvnc(vnc_hash[vm_id][:pipe]) @@ -420,5 +422,5 @@ post '/ui/stopvnc/:id' do session['vnc'].delete(vm_id) end - rc + return rc end From 9cd3d3df1b80919f3d1abecaf9c3b1d583ef4688 Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Tue, 14 Feb 2012 11:28:36 +0100 Subject: [PATCH 06/11] Add verbose option to OCCI resources --- src/cloud/occi/lib/ImageOCCI.rb | 2 +- src/cloud/occi/lib/ImagePoolOCCI.rb | 2 +- src/cloud/occi/lib/UserOCCI.rb | 2 +- src/cloud/occi/lib/UserPoolOCCI.rb | 2 +- src/cloud/occi/lib/VirtualMachineOCCI.rb | 2 +- src/cloud/occi/lib/VirtualNetworkOCCI.rb | 2 +- src/cloud/occi/lib/VirtualNetworkPoolOCCI.rb | 3 ++- 7 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/cloud/occi/lib/ImageOCCI.rb b/src/cloud/occi/lib/ImageOCCI.rb index 777876fdcd..f95f4f65bc 100755 --- a/src/cloud/occi/lib/ImageOCCI.rb +++ b/src/cloud/occi/lib/ImageOCCI.rb @@ -84,7 +84,7 @@ class ImageOCCI < Image end # Creates the OCCI representation of an Image - def to_occi(base_url) + def to_occi(base_url, verbose=false) begin occi_im = ERB.new(OCCI_IMAGE) occi_im_text = occi_im.result(binding) diff --git a/src/cloud/occi/lib/ImagePoolOCCI.rb b/src/cloud/occi/lib/ImagePoolOCCI.rb index ee38636867..db1d89d306 100755 --- a/src/cloud/occi/lib/ImagePoolOCCI.rb +++ b/src/cloud/occi/lib/ImagePoolOCCI.rb @@ -30,7 +30,7 @@ class ImagePoolOCCI < ImagePool } # Creates the OCCI representation of a Virtual Machine Pool - def to_occi(base_url) + def to_occi(base_url, verbose=false) begin occi = ERB.new(OCCI_IMAGE_POOL) occi_text = occi.result(binding) diff --git a/src/cloud/occi/lib/UserOCCI.rb b/src/cloud/occi/lib/UserOCCI.rb index fa8a960ef2..ecb71deb37 100644 --- a/src/cloud/occi/lib/UserOCCI.rb +++ b/src/cloud/occi/lib/UserOCCI.rb @@ -51,7 +51,7 @@ class UserOCCI < User end # Creates the OCCI representation of a User - def to_occi(base_url) + def to_occi(base_url, verbose=false) quota = Quota.new user_usage = quota.get_usage(self.id, nil, FORCE_USAGE) user_usage.delete(:uid) diff --git a/src/cloud/occi/lib/UserPoolOCCI.rb b/src/cloud/occi/lib/UserPoolOCCI.rb index 2745020dc7..6455a2c3b8 100644 --- a/src/cloud/occi/lib/UserPoolOCCI.rb +++ b/src/cloud/occi/lib/UserPoolOCCI.rb @@ -30,7 +30,7 @@ class UserPoolOCCI < UserPool } # Creates the OCCI representation of a User Pool - def to_occi(base_url) + def to_occi(base_url, verbose=false) begin occi = ERB.new(OCCI_USER_POOL) occi_text = occi.result(binding) diff --git a/src/cloud/occi/lib/VirtualMachineOCCI.rb b/src/cloud/occi/lib/VirtualMachineOCCI.rb index 4cb8754653..3a190e571a 100755 --- a/src/cloud/occi/lib/VirtualMachineOCCI.rb +++ b/src/cloud/occi/lib/VirtualMachineOCCI.rb @@ -122,7 +122,7 @@ class VirtualMachineOCCI < VirtualMachine end # Creates the VMI representation of a Virtual Machine - def to_occi(base_url) + def to_occi(base_url, verbose=false) begin occi_vm = ERB.new(OCCI_VM) occi_vm_text = occi_vm.result(binding) diff --git a/src/cloud/occi/lib/VirtualNetworkOCCI.rb b/src/cloud/occi/lib/VirtualNetworkOCCI.rb index 68edb59c7f..6efe071bba 100755 --- a/src/cloud/occi/lib/VirtualNetworkOCCI.rb +++ b/src/cloud/occi/lib/VirtualNetworkOCCI.rb @@ -54,7 +54,7 @@ class VirtualNetworkOCCI < VirtualNetwork end # Creates the OCCI representation of a Virtual Network - def to_occi(base_url) + def to_occi(base_url, verbose=false) network_address = nil network_size = nil diff --git a/src/cloud/occi/lib/VirtualNetworkPoolOCCI.rb b/src/cloud/occi/lib/VirtualNetworkPoolOCCI.rb index 3de2469ae9..a88fdf6d0c 100755 --- a/src/cloud/occi/lib/VirtualNetworkPoolOCCI.rb +++ b/src/cloud/occi/lib/VirtualNetworkPoolOCCI.rb @@ -31,7 +31,8 @@ class VirtualNetworkPoolOCCI < VirtualNetworkPool # Creates the OCCI representation of a Virtual Machine Pool - def to_occi(base_url)begin + def to_occi(base_url, verbose=false) + begin occi = ERB.new(OCCI_NETWORK_POOL) occi_text = occi.result(binding) rescue Exception => e From 8285b50b65be5324f10db3531e992c6ca6f756e1 Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Tue, 14 Feb 2012 11:20:10 +0100 Subject: [PATCH 07/11] Feature #1076: support full configuration response in selfservice. Plus minor fixes in occi-server (cherry picked from commit f3fe56b383f78d0795ed72b565a0325b097ffc37) --- src/cloud/occi/lib/occi-server.rb | 4 +-- src/cloud/occi/lib/ui/public/js/occi.js | 25 ++++++++++++++++ .../lib/ui/public/js/plugins/configuration.js | 29 ++++++++++++------- 3 files changed, 46 insertions(+), 12 deletions(-) diff --git a/src/cloud/occi/lib/occi-server.rb b/src/cloud/occi/lib/occi-server.rb index 047fe55cad..bf7657fa91 100755 --- a/src/cloud/occi/lib/occi-server.rb +++ b/src/cloud/occi/lib/occi-server.rb @@ -317,8 +317,8 @@ get '/ui/config' do config = "" config << " #{session[:lang]}" - congig << " #{wss}" - congig << " #{vnc}" + config << " #{wss}" + config << " #{vnc}" config << "" return [200, config] diff --git a/src/cloud/occi/lib/ui/public/js/occi.js b/src/cloud/occi/lib/ui/public/js/occi.js index 569a75e527..a818fe8008 100644 --- a/src/cloud/occi/lib/ui/public/js/occi.js +++ b/src/cloud/occi/lib/ui/public/js/occi.js @@ -342,6 +342,31 @@ var OCCI = { } }, + "Config": { + "resource": "CONFIG", + + "list": function(params){ + var callback = params.success; + var callback_error = params.error; + + var resource = OCCI.Config.resource; + var request = OCCI.Helper.request(resource,"list"); + + $.ajax({ + url: "ui/config", + type: "GET", + dataType: "xml ONEjson", + success: function(response){ + return callback ? callback(request, response) : null; + }, + error: function(response){ + return callback_error ? + callback_error(request, OCCI.Error(response)) : null; + } + }); + } + }, + "Network": { "resource": "NETWORK", diff --git a/src/cloud/occi/lib/ui/public/js/plugins/configuration.js b/src/cloud/occi/lib/ui/public/js/plugins/configuration.js index de32d3e084..900e21e32a 100644 --- a/src/cloud/occi/lib/ui/public/js/plugins/configuration.js +++ b/src/cloud/occi/lib/ui/public/js/plugins/configuration.js @@ -41,14 +41,33 @@ var config_tab_content = \ '; +var config_actions = { + "Config.list" : { + type : 'list', + call : OCCI.Config.list, + callback : updateConfig, + error : onError + }, +}; + var config_tab = { title: tr("Configuration"), content: config_tab_content } +Sunstone.addActions(config_actions); Sunstone.addMainTab('config_tab',config_tab); +function updateConfig(request, response){ + var config = response; + //These two variables defined in compute.js + vnc_enable = config['VNC'] == 'true' || config['VNC'] == 'yes' ? true : false; + use_wss = config['WSS'] == 'true' || config['WSS'] == 'yes'? true : false; +}; + $(document).ready(function(){ + Sunstone.runAction('Config.list'); + $('#li_config_tab').click(function(){ hideDialog(); }); @@ -64,14 +83,4 @@ $(document).ready(function(){ //Vendor customization, change small logo $('div#logo img').attr('src',logo_small); - - $.get('ui/config/vnc',function(response){ - if (response == "true" || response == "yes") - vnc_enable=true; //defined in compute.js - }); - - $.get('ui/config/wss', function(response){ - if (response == "true" || response == "yes") - use_wss=true; //defined in compute.js - }); }); \ No newline at end of file From 7bad159c7d8199713b09fbc4318d7524a7d44789 Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Tue, 14 Feb 2012 10:48:36 +0100 Subject: [PATCH 08/11] Feature #1069: Update config plugin to accept full configuration object. Whitespace cleanup and minor fixes in .rb files. (cherry picked from commit da1e4a822937eaa3e5a2ef4c2126a5bbde15952b) --- src/sunstone/OpenNebulaVNC.rb | 4 +-- src/sunstone/public/js/plugins/config-tab.js | 31 ++++++++++++++++---- src/sunstone/sunstone-server.rb | 12 ++++---- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/src/sunstone/OpenNebulaVNC.rb b/src/sunstone/OpenNebulaVNC.rb index ef628662f2..2da2e57d34 100644 --- a/src/sunstone/OpenNebulaVNC.rb +++ b/src/sunstone/OpenNebulaVNC.rb @@ -41,7 +41,7 @@ class OpenNebulaVNC # Start a VNC proxy def start(vm_resource) # Check configurations and VM attributes - + if @proxy_path == nil || @proxy_path.empty? return error(403,"VNC proxy not configured") end @@ -98,6 +98,6 @@ class OpenNebulaVNC return [code,msg] end end - + end diff --git a/src/sunstone/public/js/plugins/config-tab.js b/src/sunstone/public/js/plugins/config-tab.js index f342e91665..303961fb60 100644 --- a/src/sunstone/public/js/plugins/config-tab.js +++ b/src/sunstone/public/js/plugins/config-tab.js @@ -47,13 +47,33 @@ var config_tab_content = \ '; +var config_actions = { + "Config.list" : { + type: "list", + call: OpenNebula.Config.list, + callback: updateConfig, + error: onError + }, +}; + var config_tab = { title: tr("Configuration"), content: config_tab_content } +Sunstone.addActions(config_actions); Sunstone.addMainTab('config_tab',config_tab); + +function updateConfig(request,response){ + var config = response['user_config']; + + //Set wss checkbox to correct value + if (config["wss"] == "yes"){ + $('table#config_table input#wss_checkbox').attr('checked','checked'); + }; +}; + function updateWss(){ var user_info_req = { data : { @@ -84,16 +104,17 @@ function updateWss(){ }; $(document).ready(function(){ + Sunstone.runAction('Config.list'); + + //Set the language select to correct value if (lang) $('table#config_table #lang_sel option[value="'+lang+'"]').attr('selected','selected'); + + //Listener to change language $('table#config_table #lang_sel').change(function(){ setLang($(this).val()); }); + //Listener to wss change $('table#config_table #wss_checkbox').change(updateWss); - - $.get('config/wss',function(response){ - if (response != "no") - $('table#config_table input#wss_checkbox').attr('checked','checked'); - }); }); \ No newline at end of file diff --git a/src/sunstone/sunstone-server.rb b/src/sunstone/sunstone-server.rb index 62081e24f2..a2636ed929 100755 --- a/src/sunstone/sunstone-server.rb +++ b/src/sunstone/sunstone-server.rb @@ -132,7 +132,7 @@ helpers do else wss = settings.config[:vnc_proxy_support_wss] #limit to yes,no options - session[:wss] = (wss == true || wss == "yes" || wss == "only" ? + session[:wss] = (wss == true || wss == "yes" || wss == "only" ? "yes" : "no") end @@ -231,14 +231,14 @@ end ############################################################################## get '/config' do - uconf = { + uconf = { :user_config => { - :lang => session[:lang] - :wss => session[:wss] + :lang => session[:lang], + :wss => session[:wss] } - } + } - [200, uconf.json] + [200, uconf.to_json] end post '/config' do From d922575af755869ca6508a17079c650c10146eb1 Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Tue, 14 Feb 2012 11:28:36 +0100 Subject: [PATCH 09/11] Add verbose option to OCCI resources (cherry picked from commit 9cd3d3df1b80919f3d1abecaf9c3b1d583ef4688) --- src/cloud/occi/lib/ImageOCCI.rb | 2 +- src/cloud/occi/lib/ImagePoolOCCI.rb | 2 +- src/cloud/occi/lib/UserOCCI.rb | 2 +- src/cloud/occi/lib/UserPoolOCCI.rb | 2 +- src/cloud/occi/lib/VirtualMachineOCCI.rb | 2 +- src/cloud/occi/lib/VirtualNetworkOCCI.rb | 2 +- src/cloud/occi/lib/VirtualNetworkPoolOCCI.rb | 3 ++- 7 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/cloud/occi/lib/ImageOCCI.rb b/src/cloud/occi/lib/ImageOCCI.rb index 777876fdcd..f95f4f65bc 100755 --- a/src/cloud/occi/lib/ImageOCCI.rb +++ b/src/cloud/occi/lib/ImageOCCI.rb @@ -84,7 +84,7 @@ class ImageOCCI < Image end # Creates the OCCI representation of an Image - def to_occi(base_url) + def to_occi(base_url, verbose=false) begin occi_im = ERB.new(OCCI_IMAGE) occi_im_text = occi_im.result(binding) diff --git a/src/cloud/occi/lib/ImagePoolOCCI.rb b/src/cloud/occi/lib/ImagePoolOCCI.rb index ee38636867..db1d89d306 100755 --- a/src/cloud/occi/lib/ImagePoolOCCI.rb +++ b/src/cloud/occi/lib/ImagePoolOCCI.rb @@ -30,7 +30,7 @@ class ImagePoolOCCI < ImagePool } # Creates the OCCI representation of a Virtual Machine Pool - def to_occi(base_url) + def to_occi(base_url, verbose=false) begin occi = ERB.new(OCCI_IMAGE_POOL) occi_text = occi.result(binding) diff --git a/src/cloud/occi/lib/UserOCCI.rb b/src/cloud/occi/lib/UserOCCI.rb index fa8a960ef2..ecb71deb37 100644 --- a/src/cloud/occi/lib/UserOCCI.rb +++ b/src/cloud/occi/lib/UserOCCI.rb @@ -51,7 +51,7 @@ class UserOCCI < User end # Creates the OCCI representation of a User - def to_occi(base_url) + def to_occi(base_url, verbose=false) quota = Quota.new user_usage = quota.get_usage(self.id, nil, FORCE_USAGE) user_usage.delete(:uid) diff --git a/src/cloud/occi/lib/UserPoolOCCI.rb b/src/cloud/occi/lib/UserPoolOCCI.rb index 2745020dc7..6455a2c3b8 100644 --- a/src/cloud/occi/lib/UserPoolOCCI.rb +++ b/src/cloud/occi/lib/UserPoolOCCI.rb @@ -30,7 +30,7 @@ class UserPoolOCCI < UserPool } # Creates the OCCI representation of a User Pool - def to_occi(base_url) + def to_occi(base_url, verbose=false) begin occi = ERB.new(OCCI_USER_POOL) occi_text = occi.result(binding) diff --git a/src/cloud/occi/lib/VirtualMachineOCCI.rb b/src/cloud/occi/lib/VirtualMachineOCCI.rb index 4cb8754653..3a190e571a 100755 --- a/src/cloud/occi/lib/VirtualMachineOCCI.rb +++ b/src/cloud/occi/lib/VirtualMachineOCCI.rb @@ -122,7 +122,7 @@ class VirtualMachineOCCI < VirtualMachine end # Creates the VMI representation of a Virtual Machine - def to_occi(base_url) + def to_occi(base_url, verbose=false) begin occi_vm = ERB.new(OCCI_VM) occi_vm_text = occi_vm.result(binding) diff --git a/src/cloud/occi/lib/VirtualNetworkOCCI.rb b/src/cloud/occi/lib/VirtualNetworkOCCI.rb index 68edb59c7f..6efe071bba 100755 --- a/src/cloud/occi/lib/VirtualNetworkOCCI.rb +++ b/src/cloud/occi/lib/VirtualNetworkOCCI.rb @@ -54,7 +54,7 @@ class VirtualNetworkOCCI < VirtualNetwork end # Creates the OCCI representation of a Virtual Network - def to_occi(base_url) + def to_occi(base_url, verbose=false) network_address = nil network_size = nil diff --git a/src/cloud/occi/lib/VirtualNetworkPoolOCCI.rb b/src/cloud/occi/lib/VirtualNetworkPoolOCCI.rb index 3de2469ae9..a88fdf6d0c 100755 --- a/src/cloud/occi/lib/VirtualNetworkPoolOCCI.rb +++ b/src/cloud/occi/lib/VirtualNetworkPoolOCCI.rb @@ -31,7 +31,8 @@ class VirtualNetworkPoolOCCI < VirtualNetworkPool # Creates the OCCI representation of a Virtual Machine Pool - def to_occi(base_url)begin + def to_occi(base_url, verbose=false) + begin occi = ERB.new(OCCI_NETWORK_POOL) occi_text = occi.result(binding) rescue Exception => e From 0652b11c29133fcf0dcdedcba47e724bf856f936 Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Tue, 14 Feb 2012 11:59:52 +0100 Subject: [PATCH 10/11] Feature #1069: Fix typo in OpenNebulaVNC (cherry picked from commit 29ac3aa88568925b49209b55b79d4e59e587d642) --- src/sunstone/OpenNebulaVNC.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sunstone/OpenNebulaVNC.rb b/src/sunstone/OpenNebulaVNC.rb index 2da2e57d34..71c92b6fe2 100644 --- a/src/sunstone/OpenNebulaVNC.rb +++ b/src/sunstone/OpenNebulaVNC.rb @@ -71,7 +71,7 @@ class OpenNebulaVNC cmd ="#{@proxy_path} #{proxy_options} #{proxy_port} #{host}:#{vnc_port}" begin - $stderr.puts("Starting vnc proxy: #{proxy_cmd}") + $stderr.puts("Starting vnc proxy: #{cmd}") pipe = IO.popen(cmd) rescue Exception => e return [500, OpenNebula::Error.new(e.message).to_json] From d0c6453c9b02ecfd6cff36c34c90a00ff29097e3 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Tue, 14 Feb 2012 13:04:11 +0100 Subject: [PATCH 11/11] Bug: pass file object to occi.post_compute method --- src/cloud/occi/lib/occi-server.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/cloud/occi/lib/occi-server.rb b/src/cloud/occi/lib/occi-server.rb index bf7657fa91..ad51901120 100755 --- a/src/cloud/occi/lib/occi-server.rb +++ b/src/cloud/occi/lib/occi-server.rb @@ -367,9 +367,12 @@ end post '/ui/upload' do file = Tempfile.new('uploaded_image') - FileUtils.cp(request.env['rack.input'].path,file.path) - request.params['file'] = file.path #so we can re-use occi post_storage() + FileUtils.cp(request.env['rack.input'].path, file.path) + + #so we can re-use occi post_storage() + request.params['file'] = {:tempfile => file} result,rc = @occi_server.post_storage(request) + treat_response(result,rc) end