diff options
| author | Matthew Hicks <mhicks@mhicks-host.usersys.redhat.com> | 2008-06-23 15:06:37 -0400 |
|---|---|---|
| committer | Matthew Hicks <mhicks@mhicks-host.usersys.redhat.com> | 2008-06-24 08:08:25 -0400 |
| commit | 4ec70ff34acf9ef7733cf6dc606a147a9c3ca9bd (patch) | |
| tree | b410d5426238f27edba0eb031e67c13f01de829d /cloudmasterd | |
| parent | 4b539425989d8c3d10a24a988175be5ba850bbec (diff) | |
| download | tools-4ec70ff34acf9ef7733cf6dc606a147a9c3ca9bd.tar.gz tools-4ec70ff34acf9ef7733cf6dc606a147a9c3ca9bd.tar.xz tools-4ec70ff34acf9ef7733cf6dc606a147a9c3ca9bd.zip | |
Tools cleanup
Diffstat (limited to 'cloudmasterd')
| -rw-r--r-- | cloudmasterd/Manifest.txt | 1 | ||||
| -rwxr-xr-x | cloudmasterd/bin/cloudmasterd-sync | 138 | ||||
| -rwxr-xr-x | cloudmasterd/extra/cloudmasterd.redhat | 1 | ||||
| -rw-r--r-- | cloudmasterd/extra/cloudmasterd.spec | 4 | ||||
| -rw-r--r-- | cloudmasterd/lib/cloudmasterd.rb | 58 | ||||
| -rw-r--r-- | cloudmasterd/lib/cloudmasterd/syncer.rb | 171 | ||||
| -rw-r--r-- | cloudmasterd/lib/cloudmasterd/version.rb | 6 |
7 files changed, 212 insertions, 167 deletions
diff --git a/cloudmasterd/Manifest.txt b/cloudmasterd/Manifest.txt index c734bd7..6060f4e 100644 --- a/cloudmasterd/Manifest.txt +++ b/cloudmasterd/Manifest.txt @@ -14,6 +14,7 @@ extra/cloudmasterd.conf extra/cloudmasterd.redhat extra/cloudmasterd.spec lib/cloudmasterd.rb +lib/cloudmasterd/syncer.rb lib/cloudmasterd/version.rb log/debug.log primedb.rb diff --git a/cloudmasterd/bin/cloudmasterd-sync b/cloudmasterd/bin/cloudmasterd-sync index f30a6c4..1681bb0 100755 --- a/cloudmasterd/bin/cloudmasterd-sync +++ b/cloudmasterd/bin/cloudmasterd-sync @@ -1,142 +1,10 @@ #!/usr/bin/ruby require 'rubygems' -require 'open3' -require 'sqlite3' -require 'active_record' +require 'cloudmasterd/syncer' -# This is needed to let a 'kill PID' command cleanly -# kill the process without requiring -9 -Signal.trap("TERM") do - # Clean up any active record connections - ActiveRecord::Base.remove_connection - - # Cleanly exit - exit 0 -end - -def parse_hosts(func_stderr) - hosts = [] - func_stderr.split("\n").each do |host_line| - # Handle a remote exception coming from a disconnected host - if host_line.index("remote exception") then - hosts.pop() - else - hosts << host_line.split(":")[1][2..-1] - end - end - return hosts -end - -def sync_memory - current_state = {} - Open3.popen3("func '*' call virt freemem") do |stdin, stdout, stderr| - hosts = parse_hosts(stderr.read) - - # Parse out the machines that belong to each host and zip them together in a hash - stdout.read.split("\n").each_with_index do |memory, index| - current_state[hosts[index]] = memory - end - end - - Cloud.transaction do - # Sync up the DB state - delete everything first - Cloud.delete_all - - # Create the current entries - current_state.each do |host, memory| - Cloud.create :name => host, :memory => memory - end - end -end - -def sync_state - current_state = {} - Open3.popen3("func '*' call virt state") do |stdin, stdout, stderr| - hosts = parse_hosts(stderr.read) - - # Parse out the machines that belong to each host and zip them together in a hash - stdout.read.split("\n").each_with_index do |host, index| - host[1..-2].split(", ").each do |machine| - name, state = machine[1..-2].split(" ") - current_state[name] = {:state => state, :cloud => hosts[index]} unless name == "Domain-0" - end - end - end - - # Sync up the state for all the machines - Machine.find(:all).each do |machine| - if current_state.has_key?(machine.name) then - # We have a current state match for this machine - machine.update_attributes(:cloud => current_state[machine.name][:cloud], :state => current_state[machine.name][:state]) - - # Delete the key so we can determine unaccounted for machines - current_state.delete(machine.name) - else - # Not good - the machine in the DB isn't locateable - machine.update_attribute(:state, "missing") - end - end - - # We need to create an 'unknown' instance for all the remaining keys - current_state.each do |name, machine| - Machine.create :name => name, :email => "unknown", :cloud => machine[:cloud], :state => machine[:state] - end -end - -def sync_owners - # Sync up any unowned machines that now have an owner (handles race condition with syncing states) - unowned_machines = {} - Machine.find(:all, :conditions => "email = 'unknown'").each do |machine| - unowned_machines[machine.name] = machine - end - - owned_machines = {} - Machine.find(:all, :conditions => "email <> 'unknown'").each do |machine| - owned_machines[machine.name] = machine - end - - owned_machines.each do |name, machine| - if unowned_machines.has_key?(name) then - # Delete the unowned machine and update the owned one - u_machine = unowned_machines[name] - machine.update_attributes(:cloud => u_machine.cloud, :state => u_machine.state) - u_machine.destroy() - end - end -end - -# Wait until the DB is there to establish the connection -until File.exists?("/var/lib/cloudmaster.db") do - sleep 10 -end - -ActiveRecord::Base.logger = Logger.new('/var/log/cloudmasterd-sync.log', 5, 1024000) -ActiveRecord::Base.colorize_logging = false - -# Setup the database connection -ActiveRecord::Base.establish_connection( - :adapter => "sqlite3", - :dbfile => "/var/lib/cloudmaster.db" -) - -class Machine < ActiveRecord::Base - set_table_name "cloudmasterd_machine" -end - -class Cloud < ActiveRecord::Base - set_table_name "cloudmasterd_cloud" -end - -# Constantly keep the database in sync +syncer = Syncer.new() while true do - begin - sync_memory - sync_state - sync_owners - rescue Exception => e - puts "ERROR: An error occured during syncing - #{e.to_s}" - end - + syncer.run sleep 5 end diff --git a/cloudmasterd/extra/cloudmasterd.redhat b/cloudmasterd/extra/cloudmasterd.redhat index dd276a8..0021f44 100755 --- a/cloudmasterd/extra/cloudmasterd.redhat +++ b/cloudmasterd/extra/cloudmasterd.redhat @@ -19,6 +19,7 @@ CTL=cloudmasterd-ctl case "$1" in start) echo -n $"Starting cloudmasterd: " + rm /var/tmp/cloudmasterd.lock &> /dev/null /usr/bin/cloudmasterd-sync & $CTL start RETVAL=$? diff --git a/cloudmasterd/extra/cloudmasterd.spec b/cloudmasterd/extra/cloudmasterd.spec index 2fb4924..7d77ac8 100644 --- a/cloudmasterd/extra/cloudmasterd.spec +++ b/cloudmasterd/extra/cloudmasterd.spec @@ -6,10 +6,10 @@ Summary: daemon for machine configuration Name: rubygem-%{gemname} -Version: 0.1.10 +Version: 1.0.0 Release: 1%{?dist} Group: Development/Languages -License: GPLv2+ or Ruby +License: GPLv2 URL: http://cloudmasterd.rubyforge.org Source0: %{gemname}-%{version}.gem BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) diff --git a/cloudmasterd/lib/cloudmasterd.rb b/cloudmasterd/lib/cloudmasterd.rb index d82f165..b4cbf08 100644 --- a/cloudmasterd/lib/cloudmasterd.rb +++ b/cloudmasterd/lib/cloudmasterd.rb @@ -1,7 +1,3 @@ -$: << File.dirname(File.expand_path(__FILE__)) - -gem 'reststop', '~> 0.2' - require 'yaml' require 'fileutils' require 'rubygems' @@ -12,6 +8,7 @@ require 'restr' require 'xmlrpc/client' require 'sqlite3' require 'open3' +require 'cloudmasterd/syncer' Camping.goes :Cloudmasterd Cloudmasterd.picnic! @@ -137,37 +134,44 @@ module Cloudmasterd::Controllers email = input.email cobbler_profile = _get_cobbler_profile(machine_fqdn, repo) - @host = _get_best_host(cobbler_profile["virt_file_size"], cobbler_profile["virt_ram"]) - begin - _koan(@host, machine_fqdn, repo) + # Synchronize access before making the func calls + Syncer::lock do + @host = _get_best_host(cobbler_profile["virt_file_size"], cobbler_profile["virt_ram"]) + + begin + _koan(@host, machine_fqdn, repo) - Machine.create :name => machine_fqdn, :email => email, :cloud => @host, :state => "Installing" - render :_koan - rescue Exception => e - @exception = e - render :_error + Machine.create :name => machine_fqdn, :email => email, :cloud => @host, :state => "Installing" + render :_koan + rescue Exception => e + @exception = e + render :_error + end end end def destroy(name) puts "Destroying image #{name}" - Machine.find(:all, :conditions => "name = '#{name}'").each do |machine| - # If the machine is missing, don't bother remotely trying to cleanup - unless machine.state == "missing" then - # Destroy the virtual machine - `func "#{machine.cloud}" call command run "virsh destroy #{machine.name}"` - `func "#{machine.cloud}" call command run "virsh undefine #{machine.name}"` - - # Remove the auto start file if it exists - `func "#{machine.cloud}" call command run "rm -rf /etc/xen/auto/#{machine.name}"` - - # Remove the image file - `func "#{machine.cloud}" call command run "rm -rf /images/#{machine.name}-disk0"` - end - # Delete the DB record - machine.destroy + Syncer::lock do + Machine.find(:all, :conditions => "name = '#{name}'").each do |machine| + # If the machine is missing, don't bother remotely trying to cleanup + unless machine.state == "missing" then + # Destroy the virtual machine + `func "#{machine.cloud}" call command run "virsh destroy #{machine.name}"` + `func "#{machine.cloud}" call command run "virsh undefine #{machine.name}"` + + # Remove the auto start file if it exists + `func "#{machine.cloud}" call command run "rm -rf /etc/xen/auto/#{machine.name}"` + + # Remove the image file + `func "#{machine.cloud}" call command run "rm -rf /images/#{machine.name}-disk0"` + end + + # Delete the DB record + machine.destroy + end end redirect R(Status) diff --git a/cloudmasterd/lib/cloudmasterd/syncer.rb b/cloudmasterd/lib/cloudmasterd/syncer.rb new file mode 100644 index 0000000..3e9d493 --- /dev/null +++ b/cloudmasterd/lib/cloudmasterd/syncer.rb @@ -0,0 +1,171 @@ +#!/usr/bin/ruby + +require 'rubygems' +require 'open3' +require 'sqlite3' +require 'active_record' + +# This is needed to let a 'kill PID' command cleanly +# kill the process without requiring -9 +Signal.trap("TERM") do + # Clean up any active record connections + ActiveRecord::Base.remove_connection + + # Cleanly exit + exit 0 +end + +# Define the ActiveRecord classes +class Machine < ActiveRecord::Base + set_table_name "cloudmasterd_machine" +end + +class Cloud < ActiveRecord::Base + set_table_name "cloudmasterd_cloud" +end + +class Syncer + # This method makes a simple attempt to provide some locking + def self.lock + lockfile = '/var/tmp/cloudmasterd.lock' + + begin + # Wait until the lock is released + while File.exists?(lockfile) do + sleep 0.5 + end + + # Obtain the lock + File.open(lockfile, "w") {|file| file.puts Thread.object_id.to_s} + + # Make sure the lock is ours - otherwise retry + retry unless File.open(lockfile, "r").readline.chomp. == Thread.object_id.to_s + + # Do the lock processing + yield + ensure + # Make sure to delete the lock + File.delete(lockfile) + end + end + + def parse_hosts(func_stderr) + hosts = [] + func_stderr.split("\n").each do |host_line| + # Handle a remote exception coming from a disconnected host + if host_line.index("remote exception") then + hosts.pop() + else + hosts << host_line.split(":")[1][2..-1] + end + end + return hosts + end + + def sync_memory + current_state = {} + Open3.popen3("func '*' call virt freemem") do |stdin, stdout, stderr| + hosts = parse_hosts(stderr.read) + + # Parse out the machines that belong to each host and zip them together in a hash + stdout.read.split("\n").each_with_index do |memory, index| + current_state[hosts[index]] = memory + end + end + + Cloud.transaction do + # Sync up the DB state - delete everything first + Cloud.delete_all + + # Create the current entries + current_state.each do |host, memory| + Cloud.create :name => host, :memory => memory + end + end + end + + def sync_state + current_state = {} + Open3.popen3("func '*' call virt state") do |stdin, stdout, stderr| + hosts = parse_hosts(stderr.read) + + # Parse out the machines that belong to each host and zip them together in a hash + stdout.read.split("\n").each_with_index do |host, index| + host[1..-2].split(", ").each do |machine| + name, state = machine[1..-2].split(" ") + current_state[name] = {:state => state, :cloud => hosts[index]} unless name == "Domain-0" + end + end + end + + # Sync up the state for all the machines + Machine.find(:all).each do |machine| + if current_state.has_key?(machine.name) then + # We have a current state match for this machine + machine.update_attributes(:cloud => current_state[machine.name][:cloud], :state => current_state[machine.name][:state]) + + # Delete the key so we can determine unaccounted for machines + current_state.delete(machine.name) + else + # Not good - the machine in the DB isn't locateable + machine.update_attribute(:state, "missing") + end + end + + # We need to create an 'unknown' instance for all the remaining keys + current_state.each do |name, machine| + Machine.create :name => name, :email => "unknown", :cloud => machine[:cloud], :state => machine[:state] + end + end + + def sync_owners + # Sync up any unowned machines that now have an owner (handles race condition with syncing states) + unowned_machines = {} + Machine.find(:all, :conditions => "email = 'unknown'").each do |machine| + unowned_machines[machine.name] = machine + end + + owned_machines = {} + Machine.find(:all, :conditions => "email <> 'unknown'").each do |machine| + owned_machines[machine.name] = machine + end + + owned_machines.each do |name, machine| + if unowned_machines.has_key?(name) then + # Delete the unowned machine and update the owned one + u_machine = unowned_machines[name] + machine.update_attributes(:cloud => u_machine.cloud, :state => u_machine.state) + u_machine.destroy() + end + end + end + + def run + # Wait until the DB is there to establish the connection + until File.exists?("/var/lib/cloudmaster.db") do + sleep 10 + end + + ActiveRecord::Base.logger = Logger.new('/var/log/cloudmasterd-sync.log', 5, 1024000) + ActiveRecord::Base.colorize_logging = false + + # Setup the database connection + ActiveRecord::Base.establish_connection( + :adapter => "sqlite3", + :dbfile => "/var/lib/cloudmaster.db" + ) + + # Constantly keep the database in sync + while true do + begin + Syncer::lock { sync_memory } + Syncer::lock { sync_state } + Syncer::lock { sync_owners } + rescue Exception => e + puts "ERROR: An error occured during syncing - #{e.to_s}" + end + + sleep 5 + end + end +end diff --git a/cloudmasterd/lib/cloudmasterd/version.rb b/cloudmasterd/lib/cloudmasterd/version.rb index d618c1c..d25021f 100644 --- a/cloudmasterd/lib/cloudmasterd/version.rb +++ b/cloudmasterd/lib/cloudmasterd/version.rb @@ -1,8 +1,8 @@ module Cloudmasterd #:nodoc: module VERSION #:nodoc: - MAJOR = 0 - MINOR = 1 - TINY = 10 + MAJOR = 1 + MINOR = 0 + TINY = 0 STRING = [MAJOR, MINOR, TINY].join('.') end |
