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 <sseago(a)redhat.com>
---
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?((a)task.instance) ||
!quota.can_start_instance?((a)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 = [@task.instance.cloud_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([(a)task.instance.image])
+ else
+ image_providers = Set.new((a)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([(a)task.instance.hardware_profile])
+ else
+ hwp_providers =
Set.new((a)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?((a)task.instance) or
+ !acct.quota.can_start_instance?((a)task.instance)))
+ end
+
+ if pool.quota and
+ (!pool.quota.can_create_instance?((a)task.instance) or
+ !pool.quota.can_start_instance?((a)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
Show replies by date