1
0
Fork 0
mirror of https://github.com/fog/fog.git synced 2022-11-09 13:51:43 -05:00
fog--fog/lib/fog/opennebula/requests/compute/OpenNebulaVNC.rb
2014-06-16 08:32:29 +02:00

336 lines
9 KiB
Ruby

# -------------------------------------------------------------------------- #
# Copyright 2002-2014, OpenNebula Project (OpenNebula.org), C12G Labs #
# #
# 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'
#if !ONE_LOCATION
NOVNC_LOCK_FILE = "/var/lock/.novnc.lock"
#else
# NOVNC_LOCK_FILE= ONE_LOCATION + "/var/.novnc.lock"
#end
TOKEN_EXPIRE_SECONDS = 4
VNC_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
]
VAR_LOCATION = Dir.pwd + "/extras/noVNC"
SHARE_LOCATION = Dir.pwd + "/extras/noVNC"
class OpenNebulaVNC
attr_reader :proxy_port
def initialize(config, logger, options = {})
opts={ :json_errors => true,
:token_folder_name => 'sunstone_vnc_tokens'}.merge(options)
@pipe = nil
@token_folder = File.join(VAR_LOCATION, opts[:token_folder_name])
@proxy_path = File.join(SHARE_LOCATION, "websockify/websocketproxy.py")
@proxy_port = config[:vnc_proxy_port]
@proxy_ipv6 = config[:vnc_proxy_ipv6]
@wss = config[:vnc_proxy_support_wss]
@lock_file = NOVNC_LOCK_FILE
if (@wss == "yes") || (@wss == "only") || (@wss == true)
@enable_wss = true
@cert = config[:vnc_proxy_cert]
@key = config[:vnc_proxy_key]
else
@enable_wss = false
end
@options = opts
@logger = logger
end
def start
if is_running?
message="VNC server already running"
STDERR.puts message
@logger.info message
return false
end
create_token_dir
proxy_options = "--target-config=#{@token_folder} "
if @enable_wss
proxy_options << " --cert #{@cert}"
proxy_options << " --key #{@key}" if @key && @key.size > 0
proxy_options << " --ssl-only" if @wss == "only"
end
if @proxy_ipv6
proxy_options << " -6"
end
cmd ="python #{@proxy_path} #{proxy_options} #{@proxy_port}"
begin
@logger.info { "Starting VNC proxy: #{cmd}" }
pid=start_daemon(cmd, VNC_LOG)
rescue Exception => e
@logger.error e.message
return false
end
File.open(@lock_file, "w") do |f|
f.write(pid.to_s)
end
sleep 1
if !is_running?
message="Error starting VNC proxy"
STDERR.puts message
@logger.error message
File.delete(@lock_file) if File.exist?(@lock_file)
return false
end
STDOUT.puts "VNC proxy started"
true
end
def proxy(vm_resource)
# Check configurations and VM attributes
#if !is_running?
# return error(400, "VNC Proxy is not running")
#end
if !VNC_STATES.include?(vm_resource['LCM_STATE'])
return error(400,"Wrong state (#{vm_resource['LCM_STATE']}) to open a VNC session")
end
if vm_resource['TEMPLATE/GRAPHICS/TYPE'].nil? ||
vm_resource['TEMPLATE/GRAPHICS/TYPE'].downcase != "vnc"
return error(400,"VM has no VNC configured")
end
# Proxy data
host = vm_resource['HISTORY_RECORDS/HISTORY[last()]/HOSTNAME']
vnc_port = vm_resource['TEMPLATE/GRAPHICS/PORT']
vnc_pw = vm_resource['TEMPLATE/GRAPHICS/PASSWD']
# Generate token random_str: host:port
random_str = rand(36**20).to_s(36) #random string a-z0-9 length 20
token = "#{random_str}: #{host}:#{vnc_port}"
token_file = 'one-'+vm_resource['ID']
# Create token file
begin
f = File.open(File.join(@token_folder, token_file), 'w')
f.write(token)
f.close
rescue Exception => e
# @logger.error e.message
return error(500, "Cannot create VNC proxy token")
end
info = {
:proxy_port => "29876",
:password => vnc_pw,
:token => random_str,
:vm_name => vm_resource['NAME']
}
return [200, info]
end
# Delete proxy token file
def delete_token(filename)
begin
File.delete(File.join(@token_folder, filename))
rescue => e
@logger.error "Error deleting token file for VM #{vm_id}"
@logger.error e.message
end
end
def stop(force=false)
pid=get_pid
if pid
@logger.info "Killing VNC proxy"
signal=(force ? 'KILL' : 'TERM')
Process.kill(signal ,pid)
sleep 1
begin
Process.getpgid(pid)
Process.kill('KILL', pid)
rescue
end
if is_running?
message="VNC server is still running"
STDERR.puts message
logger.error message
return false
end
delete_token_dir
else
message="VNC server is not running"
@logger.info message
STDERR.puts message
end
true
end
def status
if is_running?
STDOUT.puts "VNC is running"
true
else
STDOUT.puts "VNC 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 create_token_dir
delete_token_dir
begin
Dir.mkdir(@token_folder) if !File.exist?(@token_folder)
rescue Exception => e
@logger.error "Cannot create token folder"
@logger.error e.message
end
end
def delete_token_dir
if File.exist?(@token_folder)
begin
Dir.glob("#{@token_folder}/*").each do |file|
File.delete(file)
end
rescue => e
@logger.error "Error deleting token folder"
@logger.error e.message
end
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_pid, :is_running?
if RUBY_VERSION<'1.9'
def spawn(*args)
fork {
command=args[0..-2]
# Close stdin and point out and err to log file
$stdin.close
$stdout.reopen(VNC_LOG, "a")
$stderr.reopen(VNC_LOG, "a")
# Detach process from the parent
Process.setsid
exec(*command)
}
end
end
def start_daemon(cmd, log)
options={
:pgroup => true,
:in => :close,
[:out, :err] => [log, "a"],
:close_others => true }
params=cmd.split(" ")+[options]
pid=spawn( *params )
Process.detach(pid)
pid
end
end