[Ovirt-devel] [PATCH server] forward vnc bugfix, move code to forward vnc connections to dbomatic
Mohammed Morsi
mmorsi at redhat.com
Tue Mar 10 23:15:20 UTC 2009
since a vm may be shutdown by means other than taskomatic, the code
to open / close forwarded vnc connections must be in dbomatic to
catch all cases. relies on patch to introduce vm / host history since
by the time a shutdown vm arrives in dbomatic, host has already been
disassociated
---
src/db-omatic/db_omatic.rb | 11 +++
src/db-omatic/vnc.rb | 173 +++++++++++++++++++++++++++++++++++++++++
src/task-omatic/taskomatic.rb | 5 -
src/task-omatic/vnc.rb | 151 -----------------------------------
4 files changed, 184 insertions(+), 156 deletions(-)
create mode 100644 src/db-omatic/vnc.rb
delete mode 100644 src/task-omatic/vnc.rb
diff --git a/src/db-omatic/db_omatic.rb b/src/db-omatic/db_omatic.rb
index c31577c..16a0cbf 100755
--- a/src/db-omatic/db_omatic.rb
+++ b/src/db-omatic/db_omatic.rb
@@ -1,6 +1,7 @@
#!/usr/bin/ruby
$: << File.join(File.dirname(__FILE__), "../dutils")
+$: << File.join(File.dirname(__FILE__), ".")
require "rubygems"
require "qpid"
@@ -9,6 +10,7 @@ require 'dutils'
require 'daemons'
require 'optparse'
require 'logger'
+require 'vnc'
include Daemonize
@@ -156,7 +158,10 @@ class DbOmatic < Qpid::Qmf::Console
history.save!
end
+ VmVnc.forward(vm)
elsif state != Vm::STATE_PENDING
+ VmVnc.close(vm, history)
+
unless history.nil? # throw an exception if this fails?
history.time_ended = Time.now
history.state = state
@@ -379,6 +384,12 @@ class DbOmatic < Qpid::Qmf::Console
host.save
end
+ begin
+ VmVnc.deallocate_all
+ rescue Exception => e # just log any errors here
+ @logger.error "Error with closing all VM VNCs operation: " + e
+ end
+
db_vm = Vm.find(:all)
db_vm.each do |vm|
@logger.info "Marking vm #{vm.description} as stopped."
diff --git a/src/db-omatic/vnc.rb b/src/db-omatic/vnc.rb
new file mode 100644
index 0000000..7506ba8
--- /dev/null
+++ b/src/db-omatic/vnc.rb
@@ -0,0 +1,173 @@
+# Copyright (C) 2008 Red Hat, Inc.
+# Written by Mohammed Morsi <mmorsi at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA. A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+# provides static 'forward' and 'close' methods to forward a specified vm's vnc connections
+class VmVnc
+
+ private
+
+ # TODO no ruby/libiptc wrapper exists, when
+ # it does replace iptables command w/ calls to it
+ IPTABLES_CMD='/sbin/iptables '
+
+ VNC_DEBUG = false
+
+ def self.debug(msg)
+ puts "\n" + msg + "\n" if VNC_DEBUG
+ end
+
+ def self.find_host_ip(hostname)
+ # FIXME
+ addrinfo = Socket::getaddrinfo(hostname, nil)
+ unless addrinfo.size > 0
+ raise "Could not retreive address for " + hostname
+ end
+ result = addrinfo[0][3] # return ip address of first entry
+ debug( "vm host hostname resolved to " + result.to_s )
+ return result
+ end
+
+ def self.port_open?(port)
+ cmd=IPTABLES_CMD + ' -t nat -nL '
+ debug("vncPortOpen? iptables command: " + cmd)
+
+ `#{cmd}`.each_line do |l|
+ return true if l =~ /.*#{port}.*/
+ end
+ return false
+ end
+
+ def self.allocate_forward_vnc_port(vm)
+ Vm.transaction do
+ ActiveRecord::Base.connection.execute('LOCK TABLE vms')
+ vm.forward_vnc_port = Vm.available_forward_vnc_port
+ debug("Allocating forward vnc port " + vm.forward_vnc_port.to_s)
+ vm.save!
+ end
+ end
+
+ def self.deallocate_forward_vnc_port(vm)
+ debug("Deallocating forward vnc port " + vm.forward_vnc_port.to_s)
+ vm.forward_vnc_port = nil
+ vm.save!
+ end
+
+ def self.get_forward_rules(vm, history_record = nil)
+ if history_record.nil?
+ ip = find_host_ip(vm.host.hostname)
+ vnc_port = vm.vnc_port.to_s
+ else
+ ip = find_host_ip(history_record.host.hostname)
+ vnc_port = history_record.vnc_port.to_s
+ end
+
+ return " -d " + ip + " -p tcp --dport " + vnc_port + " -j ACCEPT",
+ " -s " + ip + " -p tcp --sport " + vnc_port + " -j ACCEPT"
+ end
+
+ def self.get_nat_rules(vm, history_record = nil)
+ if history_record.nil?
+ ip = find_host_ip(vm.host.hostname)
+ vnc_port = vm.vnc_port.to_s
+ else
+ ip = find_host_ip(history_record.host.hostname)
+ vnc_port = history_record.vnc_port.to_s
+ end
+
+ server,port = get_srv('ovirt', 'tcp')
+ local_ip = find_host_ip(server)
+ return " -p tcp --dport " + vm.forward_vnc_port.to_s + " -j DNAT --to " + ip + ":" + vnc_port,
+ " -d " + ip + " -p tcp --dport " + vnc_port + " -j SNAT --to " + local_ip
+ end
+
+ def self.run_command(cmd)
+ debug("Running command " + cmd)
+ status = system(cmd)
+ raise 'Command terminated with error code ' + $?.to_s unless status
+ end
+
+ public
+
+ def self.forward(vm)
+ return unless vm.forward_vnc
+
+ allocate_forward_vnc_port(vm)
+ if port_open?(vm.forward_vnc_port)
+ deallocate_forward_vnc_port(vm)
+ raise "Port already open " + vm.forward_vnc_port.to_s
+ end
+
+ forward_rule1, forward_rule2 = get_forward_rules(vm)
+ forward_rule1 = IPTABLES_CMD + " -A FORWARD " + forward_rule1
+ forward_rule2 = IPTABLES_CMD + " -A FORWARD " + forward_rule2
+
+ prerouting_rule, postrouting_rule = get_nat_rules(vm)
+ prerouting_rule = IPTABLES_CMD + " -t nat -A PREROUTING " + prerouting_rule
+ postrouting_rule = IPTABLES_CMD + " -t nat -A POSTROUTING " + postrouting_rule
+
+ debug(" open\n forward rule 1: " + forward_rule1 +
+ "\n forward_rule 2: " + forward_rule2 +
+ "\n prerouting rule: " + prerouting_rule +
+ "\n postrouting rule: " + postrouting_rule)
+
+
+ File::open("/proc/sys/net/ipv4/ip_forward", "w") { |f| f.puts "1" }
+ run_command(forward_rule1)
+ run_command(forward_rule2)
+ run_command(prerouting_rule)
+ run_command(postrouting_rule)
+ end
+
+ def self.close(vm, history_record = nil)
+ return unless vm.forward_vnc
+
+ unless port_open?(vm.forward_vnc_port)
+ raise "Port not open " + vm.forward_vnc_port.to_s
+ end
+
+ forward_rule1, forward_rule2 = get_forward_rules(vm, history_record)
+ forward_rule1 = IPTABLES_CMD + " -D FORWARD " + forward_rule1
+ forward_rule2 = IPTABLES_CMD + " -D FORWARD " + forward_rule2
+
+ prerouting_rule, postrouting_rule = get_nat_rules(vm, history_record)
+ prerouting_rule = IPTABLES_CMD + " -t nat -D PREROUTING " + prerouting_rule
+ postrouting_rule = IPTABLES_CMD + " -t nat -D POSTROUTING " + postrouting_rule
+
+ debug(" close\n forward rule 1: " + forward_rule1 +
+ "\n forward_rule 2: " + forward_rule2 +
+ "\n prerouting rule: " + prerouting_rule +
+ "\n postrouting rule: " + postrouting_rule)
+
+ run_command(forward_rule1)
+ run_command(forward_rule2)
+ run_command(prerouting_rule)
+ run_command(postrouting_rule)
+
+
+ deallocate_forward_vnc_port(vm)
+ end
+
+ # should be used in cases which
+ # closing iptables ports is not needed
+ # (ex. on server startup)
+ def self.deallocate_all
+ Vm.find(:all).each{ |vm|
+ deallocate_forward_vnc_port(vm)
+ }
+ end
+end
diff --git a/src/task-omatic/taskomatic.rb b/src/task-omatic/taskomatic.rb
index 40d494a..7e3540c 100755
--- a/src/task-omatic/taskomatic.rb
+++ b/src/task-omatic/taskomatic.rb
@@ -33,7 +33,6 @@ include Daemonize
require 'task_vm'
require 'task_storage'
-require 'vnc'
# This sad and pathetic readjustment to ruby logger class is
# required to fix the formatting because rails does the same
@@ -283,8 +282,6 @@ class TaskOmatic
raise "Error destroying VM: #{result.text}" unless result.status == 0
end
- VmVnc.close(db_vm)
-
# undefine can fail, for instance, if we live migrated from A -> B, and
# then we are shutting down the VM on B (because it only has "transient"
# XML). Therefore, just ignore undefine errors so we do the rest
@@ -381,8 +378,6 @@ class TaskOmatic
db_vm.host_id = db_host.id
db_vm.save!
- VmVnc.forward(db_vm)
-
# We write the new state here even though dbomatic will set it soon anyway.
# This is just to let the UI know that it's good to go right away and really
# dbomatic will just write the same thing over top of it soon enough.
diff --git a/src/task-omatic/vnc.rb b/src/task-omatic/vnc.rb
deleted file mode 100644
index b0a800a..0000000
--- a/src/task-omatic/vnc.rb
+++ /dev/null
@@ -1,151 +0,0 @@
-# Copyright (C) 2008 Red Hat, Inc.
-# Written by Mohammed Morsi <mmorsi at redhat.com>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; version 2 of the License.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
-# MA 02110-1301, USA. A copy of the GNU General Public License is
-# also available at http://www.gnu.org/copyleft/gpl.html.
-
-# provides static 'forward' and 'close' methods to forward a specified vm's vnc connections
-class VmVnc
-
- private
-
- # TODO no ruby/libiptc wrapper exists, when
- # it does replace iptables command w/ calls to it
- IPTABLES_CMD='/sbin/iptables '
-
- VNC_DEBUG = false
-
- def self.debug(msg)
- puts "\n" + msg + "\n" if VNC_DEBUG
- end
-
- def self.find_host_ip(hostname)
- # FIXME
- addrinfo = Socket::getaddrinfo(hostname, nil)
- unless addrinfo.size > 0
- raise "Could not retreive address for " + hostname
- end
- result = addrinfo[0][3] # return ip address of first entry
- debug( "vm host hostname resolved to " + result.to_s )
- return result
- end
-
- def self.port_open?(port)
- cmd=IPTABLES_CMD + ' -t nat -nL '
- debug("vncPortOpen? iptables command: " + cmd)
-
- `#{cmd}`.each_line do |l|
- return true if l =~ /.*#{port}.*/
- end
- return false
- end
-
- def self.allocate_forward_vnc_port(vm)
- Vm.transaction do
- ActiveRecord::Base.connection.execute('LOCK TABLE vms')
- vm.forward_vnc_port = Vm.available_forward_vnc_port
- debug("Allocating forward vnc port " + vm.forward_vnc_port.to_s)
- vm.save!
- end
- end
-
- def self.deallocate_forward_vnc_port(vm)
- debug("Deallocating forward vnc port " + vm.forward_vnc_port.to_s)
- vm.forward_vnc_port = nil
- vm.save!
- end
-
- def self.get_forward_rules(vm)
- ip = find_host_ip(vm.host.hostname)
- return " -d " + ip + " -p tcp --dport " + vm.vnc_port.to_s + " -j ACCEPT",
- " -s " + ip + " -p tcp --sport " + vm.vnc_port.to_s + " -j ACCEPT"
- end
-
- def self.get_nat_rules(vm)
- ip = find_host_ip(vm.host.hostname)
-
- server,port = get_srv('ovirt', 'tcp')
- local_ip = find_host_ip(server)
- return " -p tcp --dport " + vm.forward_vnc_port.to_s + " -j DNAT --to " + ip + ":" + vm.vnc_port.to_s,
- " -d " + ip + " -p tcp --dport " + vm.vnc_port.to_s + " -j SNAT --to " + local_ip
- end
-
- def self.run_command(cmd)
- debug("Running command " + cmd)
- status = system(cmd)
- raise 'Command terminated with error code ' + $?.to_s unless status
- end
-
- public
-
- def self.forward(vm)
- return unless vm.forward_vnc
-
- allocate_forward_vnc_port(vm)
- if port_open?(vm.forward_vnc_port)
- deallocate_forward_vnc_port(vm)
- raise "Port already open " + vm.forward_vnc_port.to_s
- end
-
- forward_rule1, forward_rule2 = get_forward_rules(vm)
- forward_rule1 = IPTABLES_CMD + " -A FORWARD " + forward_rule1
- forward_rule2 = IPTABLES_CMD + " -A FORWARD " + forward_rule2
-
- prerouting_rule, postrouting_rule = get_nat_rules(vm)
- prerouting_rule = IPTABLES_CMD + " -t nat -A PREROUTING " + prerouting_rule
- postrouting_rule = IPTABLES_CMD + " -t nat -A POSTROUTING " + postrouting_rule
-
- debug(" open\n forward rule 1: " + forward_rule1 +
- "\n forward_rule 2: " + forward_rule2 +
- "\n prerouting rule: " + prerouting_rule +
- "\n postrouting rule: " + postrouting_rule)
-
-
- File::open("/proc/sys/net/ipv4/ip_forward", "w") { |f| f.puts "1" }
- run_command(forward_rule1)
- run_command(forward_rule2)
- run_command(prerouting_rule)
- run_command(postrouting_rule)
- end
-
- def self.close(vm)
- return unless vm.forward_vnc
-
- unless port_open?(vm.forward_vnc_port)
- raise "Port not open " + vm.forward_vnc_port.to_s
- end
-
- forward_rule1, forward_rule2 = get_forward_rules(vm)
- forward_rule1 = IPTABLES_CMD + " -D FORWARD " + forward_rule1
- forward_rule2 = IPTABLES_CMD + " -D FORWARD " + forward_rule2
-
- prerouting_rule, postrouting_rule = get_nat_rules(vm)
- prerouting_rule = IPTABLES_CMD + " -t nat -D PREROUTING " + prerouting_rule
- postrouting_rule = IPTABLES_CMD + " -t nat -D POSTROUTING " + postrouting_rule
-
- debug(" close\n forward rule 1: " + forward_rule1 +
- "\n forward_rule 2: " + forward_rule2 +
- "\n prerouting rule: " + prerouting_rule +
- "\n postrouting rule: " + postrouting_rule)
-
- run_command(forward_rule1)
- run_command(forward_rule2)
- run_command(prerouting_rule)
- run_command(postrouting_rule)
-
-
- deallocate_forward_vnc_port(vm)
- end
-end
--
1.6.0.6
More information about the ovirt-devel
mailing list