From: Ladislav Martincik <[email protected]>

---
 src/app/controllers/instances_controller.rb        |   16 +-
 src/app/controllers/pools_controller.rb            |    3 -
 src/app/util/condormatic.rb                        |  155 +------------------
 src/config/environment.rb                          |    2 +-
 src/lib/deltacloud_api/base_adapter.rb             |   23 +++
 src/lib/deltacloud_api/condor_adapter.rb           |  168 ++++++++++++++++++++
 src/lib/deltacloud_api/deltacloud_api.rb           |   31 ++++
 src/spec/lib/deltacloud_api/deltacloud_api_spec.rb |   32 ++++
 8 files changed, 266 insertions(+), 164 deletions(-)
 create mode 100644 src/lib/deltacloud_api/base_adapter.rb
 create mode 100644 src/lib/deltacloud_api/condor_adapter.rb
 create mode 100644 src/lib/deltacloud_api/deltacloud_api.rb
 create mode 100644 src/spec/lib/deltacloud_api/deltacloud_api_spec.rb

diff --git a/src/app/controllers/instances_controller.rb 
b/src/app/controllers/instances_controller.rb
index 3ffb287..9e2b193 100644
--- a/src/app/controllers/instances_controller.rb
+++ b/src/app/controllers/instances_controller.rb
@@ -19,8 +19,6 @@
 # Filters added to this controller apply to all controllers in the application.
 # Likewise, all the methods added will be available for all controllers.
 
-require 'util/condormatic'
-
 class InstancesController < ApplicationController
   before_filter :require_user, :get_nav_items
   before_filter :instance, :only => [:show, :key]
@@ -111,7 +109,7 @@ class InstancesController < ApplicationController
                                   :task_target => @instance,
                                   :action      => InstanceTask::ACTION_CREATE})
         if @task.save
-          condormatic_instance_create(@task)
+          deltacloud_api.instance_create(@task)
           if Quota.can_start_instance?(@instance, nil)
             flash[:notice] = "Instance added."
           else
@@ -167,11 +165,11 @@ class InstancesController < ApplicationController
 
       case action
         when 'stop'
-          condormatic_instance_stop(@task)
+          deltacloud_api.instance_stop(@task)
         when 'destroy'
-          condormatic_instance_destroy(@task)
+          deltacloud_api.instance_destroy(@task)
         when 'start'
-          condormatic_instance_create(@task)
+          deltacloud_api.instance_create(@task)
         else
           raise ActionError.new("Sorry, action '#{action}' is currently not 
supported by condor backend.")
       end
@@ -188,7 +186,7 @@ class InstancesController < ApplicationController
     action ='remove failed'
     raise ActionError.new("#{action} cannot be performed on this instance.") 
unless
       @instance.state == Instance::STATE_ERROR
-    condormatic_instance_reset_error(@instance)
+    deltacloud_api.instance_reset_error(@instance)
     action
   end
 
@@ -199,4 +197,8 @@ class InstancesController < ApplicationController
     require_privilege(Privilege::INSTANCE_VIEW, @instance.pool)
   end
 
+  def deltacloud_api
+    @deltacloud_api ||= DeltacloudAPI::Backend.new
+  end
+
 end
diff --git a/src/app/controllers/pools_controller.rb 
b/src/app/controllers/pools_controller.rb
index 2ba6940..1c479b0 100644
--- a/src/app/controllers/pools_controller.rb
+++ b/src/app/controllers/pools_controller.rb
@@ -19,8 +19,6 @@
 # Filters added to this controller apply to all controllers in the application.
 # Likewise, all the methods added will be available for all controllers.
 
-require 'util/condormatic'
-
 class PoolsController < ApplicationController
   before_filter :require_user, :get_nav_items
 
@@ -152,5 +150,4 @@ class PoolsController < ApplicationController
     end
     redirect_to :action => 'show', :id => @pool.id
   end
-  kick_condor
 end
diff --git a/src/app/util/condormatic.rb b/src/app/util/condormatic.rb
index 37040cd..02b7adb 100644
--- a/src/app/util/condormatic.rb
+++ b/src/app/util/condormatic.rb
@@ -20,143 +20,13 @@
 require 'nokogiri'
 require 'socket'
 
-def escape(str)
+module CondormaticHelper
+  def escape(str)
     str = str.gsub('\\', '\\\\')
     str = str.gsub(' ', '\\ ')
-end
-
-def condormatic_instance_create(task)
-
-  begin
-    instance = task.instance
-    realm = instance.realm rescue nil
-
-    job_name = "job_#{instance.name}_#{instance.id}"
-
-    instance.condor_job_id = job_name
-    instance.save!
-
-    # I use the 2>&1 to get stderr and stdout together because popen3 does not 
support
-    # the ability to get the exit value of the command in ruby 1.8.
-    pipe = IO.popen("condor_submit 2>&1", "w+")
-    pipe.puts "universe = grid\n"
-    Rails.logger.info "universe = grid\n"
-    pipe.puts "executable = #{job_name}\n"
-    Rails.logger.info "executable = #{job_name}\n"
-
-    resource = "grid_resource = dcloud $$(provider_url) $$(username) 
$$(password) $$(image_key) #{escape(instance.name)}"
-    if realm != nil
-      resource += " $$(realm_key)"
-    else
-      resource += " NULL"
-    end
-    resource += " $$(hardwareprofile_key) $$(keypair)\n"
-
-    pipe.puts resource
-    Rails.logger.info resource
-
-    requirements = "requirements = hardwareprofile == 
\"#{instance.hardware_profile.id}\" && image == \"#{instance.template.id}\""
-    requirements += " && realm == \"#{realm.id}\"" if realm != nil
-    # We may need to add some stuff to the provider classads like pool id, 
provider id etc.  This is mostly just
-    # to test and make sure this works for now.
-    requirements += " && deltacloud_quota_check(\"#{job_name}\", 
other.cloud_account_id)"
-    requirements += "\n"
-
-    pipe.puts requirements
-    Rails.logger.info requirements
-
-    pipe.puts "notification = never\n"
-    Rails.logger.info "notification = never\n"
-    pipe.puts "queue\n"
-    Rails.logger.info "queue\n"
-    pipe.close_write
-    out = pipe.read
-    pipe.close
-
-    Rails.logger.info "$? (return value?) is #{$?}"
-    raise ("Error calling condor_submit: #{out}") if $? != 0
-
-  rescue Exception => ex
-    task.state = Task::STATE_FAILED
-    Rails.logger.error ex.message
-    Rails.logger.error ex.backtrace
-  else
-    # FIXME: We're kinda lying here.. we don't know the state for the task but 
I don't think that matters so much
-    # as we are just going to use the 'task' table as a kind of audit log.
-    task.state = Task::STATE_PENDING
-  end
-  task.instance.save!
-end
-
-# JobStatus for condor jobs:
-#
-# 0 Unexpanded  U
-# 1 Idle        I
-# 2 Running     R
-# 3 Removed     X
-# 4 Completed   C
-# 5 Held        H
-# 6 Submission_err  E
-#
-
-def condor_to_instance_state(state_val)
-  case state_val
-    when '0'
-      return Instance::STATE_PENDING
-    when '1'
-      return Instance::STATE_PENDING
-    when '2'
-      return Instance::STATE_RUNNING
-    when '3'
-      return Instance::STATE_STOPPED
-    when '4'
-      return Instance::STATE_STOPPED
-    when '5'
-      return Instance::STATE_ERROR
-    when '6'
-      return Instance::STATE_CREATE_FAILED
-  else
-    return Instance::STATE_PENDING
   end
 end
 
-def condormatic_instance_stop(task)
-    instance =  task.instance_of?(InstanceTask) ? task.instance : task
-
-    Rails.logger.info("calling condor_rm -constraint 'Cmd == 
\"#{instance.condor_job_id}\"' 2>&1")
-    pipe = IO.popen("condor_rm -constraint 'Cmd == 
\"#{instance.condor_job_id}\"' 2>&1")
-    out = pipe.read
-    pipe.close
-
-    Rails.logger.info("condor_rm return status is #{$?}")
-    Rails.logger.error("Error calling condor_rm (exit code #{$?}) on job: 
#{out}") if $? != 0
-end
-
-def condormatic_instance_reset_error(instance)
-
-  condormatic_instance_stop(instance)
-    Rails.logger.info("calling condor_rm -forcex -constraint 'Cmd == 
\"#{instance.condor_job_id}\"' 2>&1")
-    pipe = IO.popen("condor_rm -forcex -constraint 'Cmd == 
\"#{instance.condor_job_id}\"' 2>&1")
-    out = pipe.read
-    pipe.close
-
-    Rails.logger.info("condor_rm return status is #{$?}")
-    Rails.logger.error("Error calling condor_rm (exit code #{$?}) on job: 
#{out}") if $? != 0
-end
-
-def condormatic_instance_destroy(task)
-    instance = task.instance
-
-    Rails.logger.info("calling condor_rm -constraint 'Cmd == 
\"#{instance.condor_job_id}\"' 2>&1")
-    pipe = IO.popen("condor_rm -constraint 'Cmd == 
\"#{instance.condor_job_id}\"' 2>&1")
-    out = pipe.read
-    pipe.close
-
-    Rails.logger.info("condor_rm return status is #{$?}")
-    Rails.logger.error("Error calling condor_rm (exit code #{$?}) on job: 
#{out}") if $? != 0
-end
-
-
 def condormatic_classads_sync
   Rails.logger.info "Starting condormatic_classads_sync..."
   index = 0
@@ -244,7 +114,6 @@ def condormatic_classads_sync
     pipe.puts "cloud_account_id=\"#{account.id}\""
     pipe.puts "keypair=\"#{escape(account.instance_key.name)}\""
     pipe.close_write
-
     out = pipe.read
     pipe.close
 
@@ -254,23 +123,3 @@ def condormatic_classads_sync
   }
   Rails.logger.info "done"
 end
-
-def kick_condor
-  begin
-    socket = Socket.new(Socket::AF_INET, Socket::SOCK_DGRAM, 0)
-    in_addr = Socket.pack_sockaddr_in(7890, 'localhost')
-    socket.connect(in_addr)
-    socket.write("kick")
-    socket.close
-  rescue
-    # if any of the above failed, it's possible that the condor_refreshd
-    # daemon is not running.  This is especially useful when running the
-    # spec tests, since you don't necessarily want condor running in that
-    # circumstance.
-    # FIXME: there are a couple of problems with ignoring errors here.  The
-    # first is that if this does actually fail, then it's unclear when in the
-    # future we will update the classads next.  The second problem is that
-    # if condor_refreshd died for some reason, but condor itself is running,
-    # condor could be running with stale data.
-  end
-end
diff --git a/src/config/environment.rb b/src/config/environment.rb
index 7d8ba2c..c3cad8b 100644
--- a/src/config/environment.rb
+++ b/src/config/environment.rb
@@ -51,7 +51,7 @@ Rails::Initializer.run do |config|
   config.gem "compass-960-plugin", :lib => "ninesixty"
   config.gem "simple-navigation"
   config.gem "typhoeus"
-  config.gem "rb-inotify"
+#  config.gem "rb-inotify"
 
   config.active_record.observers = :instance_observer, :task_observer
   # Only load the plugins named here, in the order given. By default, all 
plugins
diff --git a/src/lib/deltacloud_api/base_adapter.rb 
b/src/lib/deltacloud_api/base_adapter.rb
new file mode 100644
index 0000000..527843a
--- /dev/null
+++ b/src/lib/deltacloud_api/base_adapter.rb
@@ -0,0 +1,23 @@
+module DeltacloudAPI
+
+  class NotImplemented < Exception; end
+
+  class BaseAdapter
+    include Singleton
+
+    # Basic API methods every Adapter should implement
+    def instance_create(*args)
+      raise NotImplemented.new
+    end
+
+    def instance_stop(*args)
+      raise NotImplemented.new
+    end
+
+    def instance_destroy(*args)
+      raise NotImplemented.new
+    end
+
+  end
+
+end
diff --git a/src/lib/deltacloud_api/condor_adapter.rb 
b/src/lib/deltacloud_api/condor_adapter.rb
new file mode 100644
index 0000000..ab04afe
--- /dev/null
+++ b/src/lib/deltacloud_api/condor_adapter.rb
@@ -0,0 +1,168 @@
+module DeltacloudAPI
+  class CondorAdapter < BaseAdapter
+
+    def initialize
+      start
+    end
+
+    def instance_create(task)
+      begin
+        instance = task.instance
+        realm = instance.realm rescue nil
+
+        job_name = "job_#{instance.name}_#{instance.id}"
+
+        instance.condor_job_id = job_name
+        instance.save!
+
+        # I use the 2>&1 to get stderr and stdout together because popen3 does 
not support
+        # the ability to get the exit value of the command in ruby 1.8.
+        pipe = IO.popen("condor_submit 2>&1", "w+")
+        pipe.puts "universe = grid\n"
+        Rails.logger.info "universe = grid\n"
+        pipe.puts "executable = #{job_name}\n"
+        Rails.logger.info "executable = #{job_name}\n"
+
+        resource = "grid_resource = dcloud $$(provider_url) $$(username) 
$$(password) $$(image_key) #{escape(instance.name)}"
+        if realm != nil
+          resource += " $$(realm_key)"
+        else
+          resource += " NULL"
+        end
+        resource += " $$(hardwareprofile_key) $$(keypair)\n"
+
+        pipe.puts resource
+        Rails.logger.info resource
+
+        requirements = "requirements = hardwareprofile == 
\"#{instance.hardware_profile.id}\" && image == \"#{instance.template.id}\""
+        requirements += " && realm == \"#{realm.id}\"" if realm != nil
+        # We may need to add some stuff to the provider classads like pool id, 
provider id etc.  This is mostly just
+        # to test and make sure this works for now.
+        requirements += " && deltacloud_quota_check(\"#{job_name}\", 
other.cloud_account_id)"
+        requirements += "\n"
+
+        pipe.puts requirements
+        Rails.logger.info requirements
+
+        pipe.puts "notification = never\n"
+        Rails.logger.info "notification = never\n"
+        pipe.puts "queue\n"
+        Rails.logger.info "queue\n"
+        pipe.close_write
+        out = pipe.read
+        pipe.close
+
+        Rails.logger.info "$? (return value?) is #{$?}"
+        raise ("Error calling condor_submit: #{out}") if $? != 0
+
+      rescue Exception => ex
+        task.state = Task::STATE_FAILED
+        Rails.logger.error ex.message
+        Rails.logger.error ex.backtrace
+      else
+        # FIXME: We're kinda lying here.. we don't know the state for the task 
but I don't think that matters so much
+        # as we are just going to use the 'task' table as a kind of audit log.
+        task.state = Task::STATE_PENDING
+      end
+      task.instance.save!
+    end
+
+    def instance_stop(task)
+      instance =  task.instance_of?(InstanceTask) ? task.instance : task
+
+      Rails.logger.info("calling condor_rm -constraint 'Cmd == 
\"#{instance.condor_job_id}\"' 2>&1")
+      pipe = IO.popen("condor_rm -constraint 'Cmd == 
\"#{instance.condor_job_id}\"' 2>&1")
+      out = pipe.read
+      pipe.close
+
+      Rails.logger.info("condor_rm return status is #{$?}")
+      Rails.logger.error("Error calling condor_rm (exit code #{$?}) on job: 
#{out}") if $? != 0
+    end
+
+    def instance_reset_error(instance)
+      instance_stop(instance)
+      Rails.logger.info("calling condor_rm -forcex -constraint 'Cmd == 
\"#{instance.condor_job_id}\"' 2>&1")
+      pipe = IO.popen("condor_rm -forcex -constraint 'Cmd == 
\"#{instance.condor_job_id}\"' 2>&1")
+      out = pipe.read
+      pipe.close
+
+      Rails.logger.info("condor_rm return status is #{$?}")
+      Rails.logger.error("Error calling condor_rm (exit code #{$?}) on job: 
#{out}") if $? != 0
+    end
+
+    def instance_destroy(task)
+      instance = task.instance
+
+      Rails.logger.info("calling condor_rm -constraint 'Cmd == 
\"#{instance.condor_job_id}\"' 2>&1")
+      pipe = IO.popen("condor_rm -constraint 'Cmd == 
\"#{instance.condor_job_id}\"' 2>&1")
+      out = pipe.read
+      pipe.close
+
+      Rails.logger.info("condor_rm return status is #{$?}")
+      Rails.logger.error("Error calling condor_rm (exit code #{$?}) on job: 
#{out}") if $? != 0
+    end
+
+    private
+
+    def start
+      require 'socket'
+      begin
+        socket = Socket.new(Socket::AF_INET, Socket::SOCK_DGRAM, 0)
+        in_addr = Socket.pack_sockaddr_in(7890, 'localhost')
+        socket.connect(in_addr)
+        socket.write("kick")
+        socket.close
+      rescue
+        # if any of the above failed, it's possible that the condor_refreshd
+        # daemon is not running.  This is especially useful when running the
+        # spec tests, since you don't necessarily want condor running in that
+        # circumstance.
+        # FIXME: there are a couple of problems with ignoring errors here.  The
+        # first is that if this does actually fail, then it's unclear when in 
the
+        # future we will update the classads next.  The second problem is that
+        # if condor_refreshd died for some reason, but condor itself is 
running,
+        # condor could be running with stale data.
+      end
+    end
+
+    private
+
+    # JobStatus for condor jobs:
+    #
+    # 0 Unexpanded  U
+    # 1 Idle        I
+    # 2 Running     R
+    # 3 Removed     X
+    # 4 Completed   C
+    # 5 Held        H
+    # 6 Submission_err  E
+    #
+
+    def condor_to_instance_state(state_val)
+      case state_val
+      when '0'
+        return Instance::STATE_PENDING
+      when '1'
+        return Instance::STATE_PENDING
+      when '2'
+        return Instance::STATE_RUNNING
+      when '3'
+        return Instance::STATE_STOPPED
+      when '4'
+        return Instance::STATE_STOPPED
+      when '5'
+        return Instance::STATE_ERROR
+      when '6'
+        return Instance::STATE_CREATE_FAILED
+      else
+        return Instance::STATE_PENDING
+      end
+    end
+
+    def escape(str)
+      str = str.gsub('\\', '\\\\')
+      str = str.gsub(' ', '\\ ')
+    end
+
+  end
+end
diff --git a/src/lib/deltacloud_api/deltacloud_api.rb 
b/src/lib/deltacloud_api/deltacloud_api.rb
new file mode 100644
index 0000000..58d55b2
--- /dev/null
+++ b/src/lib/deltacloud_api/deltacloud_api.rb
@@ -0,0 +1,31 @@
+require 'singleton'
+
+module DeltacloudAPI
+
+  mattr_accessor :adapter
+  self.adapter = :condor
+
+  class Backend
+    attr_reader :adapter
+
+    def initialize(adapter = nil)
+      adapter = "#{adapter || DeltacloudAPI.adapter}_adapter"
+      adapter_clazz = "DeltacloudAPI::#{adapter.camelize}"
+
+      # All adapters should behave as Singleton object
+      @adapter = adapter_clazz.constantize.instance
+    rescue NameError
+      # Try to require it before exiting with error
+      require File.join(Rails.root, 'lib', 'deltacloud_api', adapter)
+      @adapter = adapter_clazz.constantize.instance
+    end
+
+    # For now we pass everything to adapter
+    # TODO: Should be restricted API based on BaseAdapter
+    def method_missing(sym, *args, &block)
+      @adapter.__send__(sym, *args, &block)
+    end
+
+  end
+
+end
diff --git a/src/spec/lib/deltacloud_api/deltacloud_api_spec.rb 
b/src/spec/lib/deltacloud_api/deltacloud_api_spec.rb
new file mode 100644
index 0000000..3a5e8c0
--- /dev/null
+++ b/src/spec/lib/deltacloud_api/deltacloud_api_spec.rb
@@ -0,0 +1,32 @@
+require 'spec_helper'
+require 'deltacloud_api/deltacloud_api'
+
+describe DeltacloudAPI::Backend do
+  after do
+    DeltacloudAPI.adapter = :condor
+  end
+
+  it "correctly loads default backend adapter" do
+    backend = DeltacloudAPI::Backend.new
+    backend.adapter.should be_a_kind_of DeltacloudAPI::CondorAdapter
+  end
+
+  it "correctly loads non default backend adapter" do
+    class ::DeltacloudAPI::LocalMockAdapter < ::DeltacloudAPI::BaseAdapter; end
+    DeltacloudAPI.adapter = :local_mock
+    backend = DeltacloudAPI::Backend.new
+    backend.adapter.should be_a_kind_of ::DeltacloudAPI::LocalMockAdapter
+  end
+
+  it "throws exceptions if adapter not present" do
+    DeltacloudAPI.adapter = :nonsense_1234
+    lambda do
+      backend = DeltacloudAPI::Backend.new
+    end.should raise_error MissingSourceFile
+  end
+
+  it "forwards all non defined calls to adapter" do
+    backend = DeltacloudAPI::Backend.new
+  end
+
+end
-- 
1.7.3.2

_______________________________________________
deltacloud-devel mailing list
[email protected]
https://fedorahosted.org/mailman/listinfo/deltacloud-devel

Reply via email to