Note that this is not part of the condor infrastructure -- it's an interim 
solution to handle scheduling across providers until the full scheduling 
capabilities are put into use with Condor integration.

The full list of provider accounts is filtered by realm, hardware profile, and 
image -- so only those accounts that map validly to the "front-end/engine" 
realm/hwp/image choices of the user are considered. After this, we filter out 
those cloud accounts that do not have the available capacity to schedule the 
instance creation request.

As we do not  yet have a UI to map images and HWPs from different providers to 
the same front-end image or HWP, multi-provider scheduling is only possible 
across accounts in the same provider, or across providers after manually 
mapping equivalent images and HWPs.

For a simple test case with exactly two providers in the AR database with the 
same set of available images and HWPs (this will only be true for two mock 
providers, or if you've set up two separate provider objects pointing to the 
same driver -- or two drivers pointing to the same cloud impl), the following 
should take your separately-mapped resources and map them together on the front 
end:

Provider.last.images.each do  |image|
  if image.aggregator_images[0].provider_images.size < 2
    image.aggregator_images[0].delete
    image.aggregator_images = 
[Provider.first.images.find_by_external_key(image.external_key).aggregator_images[0]]
    image.save
  end
  agg_image = image.aggregator_images[0]
  agg_image.name = image.name
  agg_image.external_key = image.external_key
  agg_image.save
end

Provider.last.hardware_profiles.each do  |hardware_profile|
  if 
hardware_profile.aggregator_hardware_profiles[0].provider_hardware_profiles.size
 < 2
    hardware_profile.aggregator_hardware_profiles[0].delete
    hardware_profile.aggregator_hardware_profiles = 
[Provider.first.hardware_profiles.find_by_external_key(hardware_profile.external_key).aggregator_hardware_profiles[0]]
    hardware_profile.save
  end
  agg_hwp = hardware_profile.aggregator_hardware_profiles[0]
  agg_hwp.name = hardware_profile.name
  agg_hwp.external_key = hardware_profile.external_key
  agg_hwp.save
end

Signed-off-by: Scott Seago <[email protected]>
---
 src/app/models/instance.rb          |   14 +++---
 src/app/util/taskomatic.rb          |   77 ++++++++++++++++++++++++----------
 src/app/views/instance/new.html.erb |    2 +-
 3 files changed, 62 insertions(+), 31 deletions(-)

diff --git a/src/app/models/instance.rb b/src/app/models/instance.rb
index 21a5cef..56019ff 100644
--- a/src/app/models/instance.rb
+++ b/src/app/models/instance.rb
@@ -45,8 +45,6 @@ class Instance < ActiveRecord::Base
   validates_uniqueness_of :name, :scope => :pool_id
   validates_length_of :name, :maximum => 1024
 
-  # FIXME: for now, hardware profile is required, realm is optional, although 
for RHEV-M,
-  # hardware profile may be optional too
   validates_presence_of :hardware_profile_id
   validates_presence_of :image_id
 
@@ -114,11 +112,13 @@ class Instance < ActiveRecord::Base
   end
 
   def front_end_realm=(realm_name)
-    provider_name, tmpstr = 
realm_name.split(Realm::AGGREGATOR_REALM_PROVIDER_DELIMITER,2)
-    account_name, realm_name = 
tmpstr.split(Realm::AGGREGATOR_REALM_ACCOUNT_DELIMITER,2)
-    provider = Provider.find_by_name(provider_name)
-    self.cloud_account = provider.cloud_accounts.find_by_username(account_name)
-    self.realm = provider.realms.find_by_name(realm_name) unless 
realm_name.nil?
+    unless realm_name.nil? or realm_name.empty?
+      provider_name, tmpstr = 
realm_name.split(Realm::AGGREGATOR_REALM_PROVIDER_DELIMITER,2)
+      account_name, realm_name = 
tmpstr.split(Realm::AGGREGATOR_REALM_ACCOUNT_DELIMITER,2)
+      provider = Provider.find_by_name(provider_name)
+      self.cloud_account = 
provider.cloud_accounts.find_by_username(account_name)
+      self.realm = provider.realms.find_by_name(realm_name) unless 
realm_name.nil?
+    end
   end
 
   # Returns the total time that this instance has been in the state
diff --git a/src/app/util/taskomatic.rb b/src/app/util/taskomatic.rb
index 3277c4d..08da3d2 100644
--- a/src/app/util/taskomatic.rb
+++ b/src/app/util/taskomatic.rb
@@ -50,40 +50,71 @@ class Taskomatic
     # can go to state running.
     # TODO Modify this to handle generic case for providers
     pool = @task.instance.pool
-    cloud_account = @task.instance.cloud_account
 
-    [pool, cloud_account].each do |parent|
-      quota = parent.quota
-      if quota
-        if !quota.can_create_instance?(@task.instance) || 
!quota.can_start_instance?(@task.instance)
-          @task.state = Task::STATE_FAILED
-          @task.instance.state = Instance::STATE_CREATE_FAILED
+    #find matching cloud account
+    if @task.instance.cloud_account
+      cloud_accounts = [[email protected]_account]
+    else
+      # FIXME: this provides a predictable order -- scheduler will eventually
+      # do something entirely different to determine preference
+      cloud_accounts = CloudAccount.find(:all, :order => 'created_at')
+    end
 
-          if parent.class == Pool
-            @task.failure_code =  Task::FAILURE_OVER_POOL_QUOTA
-          elsif parent.class == CloudAccount
-            @task.failure_code =  Task::FAILURE_OVER_CLOUD_ACCOUNT_QUOTA
-          end
+    if @task.instance.image.provider_image?
+      image_providers = Set.new([[email protected]])
+    else
+      image_providers = Set.new(@task.instance.image.provider_images.
+                                 collect { |image| image.provider})
+    end
 
-          @task.save!
-          @task.instance.save!
+    if @task.instance.hardware_profile.provider_hardware_profile?
+      hwp_providers = Set.new([[email protected]_profile])
+    else
+      hwp_providers = 
Set.new(@task.instance.hardware_profile.provider_hardware_profiles.
+                              collect { |hwp| hwp.provider })
+    end
 
-          return @task
-        end
-      end
+    matching_providers = hwp_providers & image_providers
+    cloud_accounts.delete_if do |acct|
+      !matching_providers.include?(acct.provider) or
+        (acct.quota and
+         (!acct.quota.can_create_instance?(@task.instance) or
+          !acct.quota.can_start_instance?(@task.instance)))
+    end
+
+    if pool.quota and
+        (!pool.quota.can_create_instance?(@task.instance) or
+         !pool.quota.can_start_instance?(@task.instance))
+      @task.failure_code =  Task::FAILURE_OVER_POOL_QUOTA
+    end
+    @task.failure_code = Task::FAILURE_PROVIDER_NOT_FOUND if 
cloud_accounts.empty?
+
+    unless @task.failure_code.nil?
+      @task.state = Task::STATE_FAILED
+      @task.instance.state = Instance::STATE_CREATE_FAILED
+      @task.save!
+      @task.instance.save!
+      return @task
     end
 
     begin
+      # take first matching cloud account
+      @task.instance.cloud_account = cloud_accounts[0]
       client = @task.instance.cloud_account.connect
       realm = @task.instance.realm.external_key rescue nil
 
       # Map aggregator HWP/image to back-end provider HWP/image in instance
       unless @task.instance.image.provider_image?
-        @task.instance.image = @task.instance.image.provider_images[0]
+        @task.instance.image = @task.instance.image.provider_images.
+          find(:first, :conditions => {:provider_id =>
+                 @task.instance.cloud_account.provider_id})
       end
 
       unless @task.instance.hardware_profile.provider_hardware_profile?
-        @task.instance.hardware_profile = 
@task.instance.hardware_profile.provider_hardware_profiles[0]
+        @task.instance.hardware_profile = @task.instance.hardware_profile.
+          provider_hardware_profiles.
+          find(:first, :conditions => {:provider_id =>
+                 @task.instance.cloud_account.provider_id})
       end
 
       @task.state = Task::STATE_PENDING
diff --git a/src/app/views/instance/new.html.erb 
b/src/app/views/instance/new.html.erb
index 894d1b6..74096a2 100644
--- a/src/app/views/instance/new.html.erb
+++ b/src/app/views/instance/new.html.erb
@@ -55,7 +55,7 @@
     <% end %>
     <% if @instance.pool and @instance.pool.realms.size > 0 %>
       <li><label>Realm<span>Choose a realm</span></label>
-        <%= select("instance", "front_end_realm", @instance.pool.realms, { 
:include_blank => false }) %>
+        <%= select("instance", "front_end_realm", @instance.pool.realms, { 
:include_blank => true }) %>
       </li>
     <% end %>
   </ul>
-- 
1.6.2.5

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

Reply via email to