https://bugzilla.redhat.com/show_bug.cgi?id=772644
Added provider_account association to provider realm, when updating realms, check all
provider accounts. In launch matching, take this association into account.
The reason for this change is that it's possible that different provider accounts will
restrict access to a subset of total realms. The prior model did not take this into
account.
---
.../controllers/provider_accounts_controller.rb | 1 +
src/app/controllers/provider_realms_controller.rb | 68 ++++++++++++++++++++
src/app/controllers/providers_controller.rb | 5 +-
src/app/helpers/provider_realms_helper.rb | 22 ++++++
src/app/models/provider.rb | 60 +++++++++++++++++
src/app/models/provider_account.rb | 41 ++++--------
src/app/models/realm.rb | 20 +++++-
src/app/views/provider_accounts/show.html.haml | 7 ++
src/app/views/provider_realms/_list.html.haml | 22 ++++++
src/app/views/provider_realms/_mapping.html.haml | 20 ++++++
.../views/provider_realms/_properties.html.haml | 12 ++++
.../provider_realms/_section_header.html.haml | 4 +
src/app/views/provider_realms/index.html.haml | 2 +
src/app/views/provider_realms/show.html.haml | 17 +++++
src/app/views/realms/_mapping.html.haml | 2 +-
src/config/routes.rb | 4 +
.../20120118221000_add_provider_accounts_realms.rb | 38 +++++++++++
src/spec/models/provider_account_spec.rb | 2 +-
18 files changed, 310 insertions(+), 37 deletions(-)
create mode 100644 src/app/controllers/provider_realms_controller.rb
create mode 100644 src/app/helpers/provider_realms_helper.rb
create mode 100644 src/app/views/provider_realms/_list.html.haml
create mode 100644 src/app/views/provider_realms/_mapping.html.haml
create mode 100644 src/app/views/provider_realms/_properties.html.haml
create mode 100644 src/app/views/provider_realms/_section_header.html.haml
create mode 100644 src/app/views/provider_realms/index.html.haml
create mode 100644 src/app/views/provider_realms/show.html.haml
create mode 100644 src/db/migrate/20120118221000_add_provider_accounts_realms.rb
diff --git a/src/app/controllers/provider_accounts_controller.rb
b/src/app/controllers/provider_accounts_controller.rb
index 6aebbac..9b5517d 100644
--- a/src/app/controllers/provider_accounts_controller.rb
+++ b/src/app/controllers/provider_accounts_controller.rb
@@ -34,6 +34,7 @@ class ProviderAccountsController < ApplicationController
@tab_captions = [t('provider_accounts.tab_captions.properties'),
t('provider_accounts.tab_captions.credentials'),
t('provider_accounts.tab_captions.history'),
t('provider_accounts.tab_captions.permissions')]
@provider_account = ProviderAccount.find(params[:id])
@provider = Provider.find(params[:provider_id])
+ @realms = @provider_account.realms
@account_id = @provider_account.credentials_hash['account_id']
require_privilege(Privilege::VIEW, @provider_account)
@details_tab = params[:details_tab].blank? ? 'properties' :
params[:details_tab]
diff --git a/src/app/controllers/provider_realms_controller.rb
b/src/app/controllers/provider_realms_controller.rb
new file mode 100644
index 0000000..6253a17
--- /dev/null
+++ b/src/app/controllers/provider_realms_controller.rb
@@ -0,0 +1,68 @@
+#
+# Copyright 2012 Red Hat, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#
http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class ProviderRealmsController < ApplicationController
+ before_filter :require_user
+ before_filter :load_realms, :only =>[:index, :show]
+
+ def index
+ clear_breadcrumbs
+ save_breadcrumb(provider_realms_path)
+ set_admin_content_tabs 'realms'
+ respond_to do |format|
+ format.html
+ format.js { render :partial => 'list' }
+ end
+ end
+
+ def show
+ @realm = Realm.find(params[:id])
+
+ @tab_captions = [t('realms.tab_captions.properties'),
t('realms.tab_captions.mapping')]
+ @details_tab = params[:details_tab].blank? ? 'properties' :
params[:details_tab]
+
+ @frontend_realms_for_provider = @realm.provider.frontend_realms
+ @frontend_realms = @realm.frontend_realms
+ @provider_accounts = @realm.provider_accounts
+
+ save_breadcrumb(provider_realm_path(@realm), @realm.name)
+
+ respond_to do |format|
+ format.html { render :action => 'show' }
+ format.js do
+ if params.delete :details_pane
+ render :partial => 'layouts/details_pane' and return
+ end
+ render :partial => @details_tab
+ end
+ format.json { render :json => @realm }
+ end
+ end
+
+ def filter
+ redirect_to_original({"provider_realms_preset_filter" =>
params[:realms_preset_filter], "realms_search" =>
params[:provider_realms_search]})
+ end
+
+ protected
+
+ def load_realms
+ @header = [
+ {:name => '', :sortable => false},
+ {:name => t("realms.index.realm_name"), :sort_attr => :name},
+ ]
+ @realms = Realm.apply_filters(:preset_filter_id =>
params[:provider_realms_preset_filter], :search_filter =>
params[:provider_realms_search])
+ end
+end
diff --git a/src/app/controllers/providers_controller.rb
b/src/app/controllers/providers_controller.rb
index c7c1e0a..35a6eae 100644
--- a/src/app/controllers/providers_controller.rb
+++ b/src/app/controllers/providers_controller.rb
@@ -211,12 +211,11 @@ class ProvidersController < ApplicationController
end
def load_provider_tabs
- #frontend realms associated to provider or a realm of this provider, with applied
filters
- @realms = FrontendRealm.includes({:backend_realms => :provider},
:backend_providers).where("providers.id = :provider_id or
(realm_backend_targets.realm_or_provider_id = :provider_id and
realm_backend_targets.realm_or_provider_type = :provider_type)", :provider_id =>
@provider.id, :provider_type => 'Provider').apply_filters(:preset_filter_id
=> params[:realms_preset_filter], :search_filter => params[:realms_search])
+ @realms = @provider.realms.apply_filters(:preset_filter_id =>
params[:provider_realms_preset_filter], :search_filter =>
params[:provider_realms_search])
#TODO add links to real data for history,properties,permissions
@tabs = [{:name => t('connectivity'), :view => 'edit', :id
=> 'connectivity'},
{:name => t('accounts'), :view =>
'provider_accounts/list', :id => 'accounts', :count =>
@provider.provider_accounts.count},
- {:name => t('realm_s'), :view => 'realms/list', :id
=> 'realms', :count => @realms.count},
+ {:name => t('realm_s'), :view =>
'provider_realms/list', :id => 'realms', :count => @realms.count},
#{:name => 'Roles & Permissions', :view => @view, :id
=> 'roles', :count => @provider.permissions.count},
]
add_permissions_tab(@provider, "edit_")
diff --git a/src/app/helpers/provider_realms_helper.rb
b/src/app/helpers/provider_realms_helper.rb
new file mode 100644
index 0000000..5a4151e
--- /dev/null
+++ b/src/app/helpers/provider_realms_helper.rb
@@ -0,0 +1,22 @@
+#
+# Copyright 2012 Red Hat, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#
http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+module ProviderRealmsHelper
+ def provider_realms_header
+ [
+ {:name => t("realms.index.realm_name"), :sort_attr => :name}
+ ]
+ end
+end
diff --git a/src/app/models/provider.rb b/src/app/models/provider.rb
index 769962b..01c0d3e 100644
--- a/src/app/models/provider.rb
+++ b/src/app/models/provider.rb
@@ -132,6 +132,66 @@ class Provider < ActiveRecord::Base
errs
end
+ def populate_realms
+ reload
+ conductor_acct_realms = {}
+ conductor_acct_realm_ids = {}
+ deltacloud_realms = []
+ dc_acct_realms = {}
+ dc_acct_realm_ids = {}
+ self.transaction do
+ provider_accounts.each do |acct|
+ client = acct.connect
+ dc_acct_realms[acct.label] = client.realms
+ dc_acct_realm_ids[acct.label] = dc_acct_realms[acct.label].collect{|r| r.id}
+ dc_acct_realms[acct.label].each do |dc_realm|
+ if deltacloud_realms.select {|r| r.id == dc_realm.id }.empty?
+ deltacloud_realms << dc_realm
+ end
+ end
+ conductor_acct_realms[acct.label] = acct.realms
+ conductor_acct_realm_ids[acct.label] =
conductor_acct_realms[acct.label].collect{|r| r.external_key}
+
+ # Remove any provider account mappings in Conductor that aren't in
Deltacloud
+ conductor_acct_realms[acct.label].each do |c_realm|
+ unless dc_acct_realm_ids[acct.label].include?(c_realm.external_key)
+ acct.realms.delete(c_realm)
+ end
+ end
+ end
+ deltacloud_realm_ids = deltacloud_realms.collect{|r| r.id}
+ # Delete anything in Conductor that's not in Deltacloud
+ conductor_realms = realms
+ conductor_realm_ids = conductor_realms.collect{|r| r.external_key}
+ conductor_realms.each do |c_realm|
+ unless deltacloud_realm_ids.include?(c_realm.external_key)
+ #c_realm.reload
+ c_realm.destroy
+ end
+ end
+
+ # Add anything in Deltacloud to Conductor if it's not already there
+ deltacloud_realms.each do |d_realm|
+ unless conductor_realm_ids.include?(d_realm.id)
+ ar_realm = Realm.new(:external_key => d_realm.id,
+ :name => d_realm.name ? d_realm.name : d_realm.id,
+ :provider_id => id)
+ ar_realm.save!
+ end
+ end
+
+ # add any new provider account realm mappings
+ provider_accounts.each do |acct|
+ dc_acct_realms[acct.label].each do |d_realm|
+ unless conductor_acct_realm_ids[acct.label].include?(d_realm.id)
+ acct.realms << realms.where("external_key" => d_realm.id)
+ end
+ end
+ end
+ end
+
+ end
+
protected
def validate_provider
if !nil_or_empty(url)
diff --git a/src/app/models/provider_account.rb b/src/app/models/provider_account.rb
index f076657..07e5014 100644
--- a/src/app/models/provider_account.rb
+++ b/src/app/models/provider_account.rb
@@ -44,6 +44,7 @@ class ProviderAccount < ActiveRecord::Base
belongs_to :quota, :autosave => true, :dependent => :destroy
has_many :instances
has_and_belongs_to_many :pool_families, :uniq => true
+ has_and_belongs_to_many :realms, :uniq => true
has_many :permissions, :as => :permission_object, :dependent => :destroy,
:include => [:role],
:order => "permissions.id ASC"
@@ -67,7 +68,8 @@ class ProviderAccount < ActiveRecord::Base
validate :validate_unique_username
validates :priority, :numericality => { :only_integer => true}, :allow_blank
=> true
- before_create :populate_profiles_and_realms
+ before_create :populate_profiles_and_validate
+ after_create :populate_realms_and_validate
before_destroy :destroyable?
scope :enabled, lambda { where(:provider_id => Provider.enabled) }
@@ -148,47 +150,28 @@ class ProviderAccount < ActiveRecord::Base
label.blank? ? credentials_hash['username'] : label
end
- def populate_profiles_and_realms
+ def populate_profiles_and_validate
begin
populate_hardware_profiles
rescue
errors.add(:base,
I18n.t("provider_accounts.errors.populate_hardware_profiles_failed", :message
=> $!.message))
return false
end
+ true
+ end
+
+ def populate_realms_and_validate
begin
populate_realms
rescue
errors.add(:base,
I18n.t("provider_accounts.errors.populate_realms_failed", :message =>
$!.message))
- return false
+ raise
end
true
end
def populate_realms
- client = connect
- deltacloud_realms = client.realms
- conductor_realms = Realm.where(:provider_id => provider.id)
- deltacloud_realm_ids = deltacloud_realms.collect{|r| r.id}
- conductor_realm_ids = conductor_realms.collect{|r| r.external_key}
-
- # I don't know if this transaction is really necessary, but it was here so
let's keep it.
- self.transaction do
- # Delete anything in Conductor that's not in Deltacloud
- conductor_realms.each do |c_realm|
- c_realm.destroy unless deltacloud_realm_ids.include?(c_realm.external_key)
- end
-
- # Add anything in Deltacloud to Conductor if it's not already there
- deltacloud_realms.each do |d_realm|
- unless conductor_realm_ids.include?(d_realm.id)
- ar_realm = Realm.new(:external_key => d_realm.id,
- :name => d_realm.name ? d_realm.name : d_realm.id,
- :provider_id => provider.id)
- ar_realm.save!
- end
- end
- end
-
+ provider.populate_realms
end
def valid_credentials?
@@ -362,7 +345,9 @@ class ProviderAccount < ActiveRecord::Base
next
end
brealms.each do |brealm_target|
- matched << Instance::Match.new(instance.pool.pool_family, self, hwp,
pi, brealm_target.target_realm)
+ if (brealm_target.target_realm.nil? ||
realms.include?(brealm_target.target_realm))
+ matched << Instance::Match.new(instance.pool.pool_family, self, hwp,
pi, brealm_target.target_realm)
+ end
end
else
matched << Instance::Match.new(instance.pool.pool_family, self, hwp, pi,
nil)
diff --git a/src/app/models/realm.rb b/src/app/models/realm.rb
index bf09b59..eb6580c 100644
--- a/src/app/models/realm.rb
+++ b/src/app/models/realm.rb
@@ -32,7 +32,11 @@
# Likewise, all the methods added will be available for all controllers.
class Realm < ActiveRecord::Base
+ class << self
+ include CommonFilterMethods
+ end
belongs_to :provider
+ has_and_belongs_to_many :provider_accounts, :uniq => true
has_many :realm_backend_targets, :as => :realm_or_provider, :dependent =>
:destroy
has_many :frontend_realms, :through => :realm_backend_targets
@@ -45,6 +49,7 @@ class Realm < ActiveRecord::Base
CONDUCTOR_REALM_PROVIDER_DELIMITER = ":"
CONDUCTOR_REALM_ACCOUNT_DELIMITER = "/"
+ PRESET_FILTERS_OPTIONS = []
def name_with_provider
"#{self.provider.name}: #{self.name}"
@@ -55,11 +60,18 @@ class Realm < ActiveRecord::Base
def self.scan_for_new
providers = Provider.all(:include => :provider_accounts)
providers.each do |provider|
- # Some providers require authentication to fetch realms, so skip those that
don't have accounts:
- acct = provider.provider_accounts.first
- next unless acct.present?
- acct.populate_realms
+ provider.populate_realms
end
true
end
+
+ private
+
+ def self.apply_search_filter(search)
+ if search
+ where("lower(name) LIKE :search", :search =>
"%#{search.downcase}%")
+ else
+ scoped
+ end
+ end
end
diff --git a/src/app/views/provider_accounts/show.html.haml
b/src/app/views/provider_accounts/show.html.haml
index 6961491..acffbce 100644
--- a/src/app/views/provider_accounts/show.html.haml
+++ b/src/app/views/provider_accounts/show.html.haml
@@ -17,3 +17,10 @@
.content
= render :partial => 'properties'
+
+%section.admin-content-section.realm
+ %header
+ %h2= t'realm_s'
+
+ .content
+ = render :partial => 'provider_realms/list'
diff --git a/src/app/views/provider_realms/_list.html.haml
b/src/app/views/provider_realms/_list.html.haml
new file mode 100644
index 0000000..cea3e77
--- /dev/null
+++ b/src/app/views/provider_realms/_list.html.haml
@@ -0,0 +1,22 @@
+- content_for :filter_controls do
+ %li
+ = label_tag :provider_realms_preset_filter, t('filter_table.viewing')
+ = hidden_field_tag :current_path, request.fullpath
+ = select_tag(:provider_realms_preset_filter,
preset_filters_options_for_select(Realm::PRESET_FILTERS_OPTIONS,
params[:realms_preset_filter]), :include_blank =>
t("realms.preset_filters.all_realms"), :disabled => true)
+ = restful_submit_tag t("filter_table.apply_filters"), "index",
filter_provider_realms_path, 'POST', :class => 'button', :id =>
'apply_provider_realms_preset_filter'
+ %span.label.badge.dark= @realms.count
+ %li.table-search-filter
+ = text_field_tag :realms_search, params[:provider_realms_search], :placeholder =>
t("filter_table.search")
+ = restful_submit_tag "", "index", filter_provider_realms_path,
'POST', :class => 'button', :id =>
'apply_provider_realms_search'
+
+ :javascript
+ $(document).ready(function(){
+ $("#apply_provider_realms_preset_filter").hide();
+ $("#provider_realms_preset_filter").change(function() {
+ $("#apply_provider_realms_preset_filter").click();
+ });
+ });
+
+= filter_table(provider_realms_header, @realms) do |realm|
+ %tr{:class => cycle('nostripe','stripe')}
+ %td= link_to realm.name, provider_realm_path(realm)
diff --git a/src/app/views/provider_realms/_mapping.html.haml
b/src/app/views/provider_realms/_mapping.html.haml
new file mode 100644
index 0000000..f83f709
--- /dev/null
+++ b/src/app/views/provider_realms/_mapping.html.haml
@@ -0,0 +1,20 @@
+- unless @frontend_realms_for_provider.empty?
+ %h2= t('realms.mapping.frontend_realms_mapped_to_provider', :name=>
"#{(a)realm.provider.name}")
+ %table.flat.checkbox_table
+ - @frontend_realms_for_provider.each do |realm|
+ %tr{:class => cycle('nostripe','stripe')}
+ %td= realm.name
+
+- unless @frontend_realms.empty?
+ %h2= t('realms.mapping.frontend_realms_mapped_to_realm', :name=>
"#{(a)realm.name}")
+ %table.flat.checkbox_table
+ - @frontend_realms.each do |realm|
+ %tr{:class => cycle('nostripe','stripe')}
+ %td= realm.name
+
+- unless @provider_accounts.empty?
+ %h2= t('realms.mapping.provider_accounts_mapped_to_realm', :name=>
"#{(a)realm.name}")
+ %table.flat.checkbox_table
+ - @provider_accounts.each do |account|
+ %tr{:class => cycle('nostripe','stripe')}
+ %td= account.label
diff --git a/src/app/views/provider_realms/_properties.html.haml
b/src/app/views/provider_realms/_properties.html.haml
new file mode 100644
index 0000000..051c8aa
--- /dev/null
+++ b/src/app/views/provider_realms/_properties.html.haml
@@ -0,0 +1,12 @@
+%table
+ %thead
+ %tr
+ %th.show
+ =t 'realms.properties.realm_details'
+ %th.show
+ %tbody
+ %tr
+ %td
+ %label= t'realms.properties.realm_name'
+ %td
+ = @realm.name
diff --git a/src/app/views/provider_realms/_section_header.html.haml
b/src/app/views/provider_realms/_section_header.html.haml
new file mode 100644
index 0000000..0cb1d75
--- /dev/null
+++ b/src/app/views/provider_realms/_section_header.html.haml
@@ -0,0 +1,4 @@
+%header.admin-page-header
+ %h1{:class => controller.controller_name} Realms
+ #obj_actions.button-group
+ = link_to t('realms.new_realm'), new_realm_url, :class => 'button
primary', :id => 'new_realm_button'
diff --git a/src/app/views/provider_realms/index.html.haml
b/src/app/views/provider_realms/index.html.haml
new file mode 100644
index 0000000..947fd74
--- /dev/null
+++ b/src/app/views/provider_realms/index.html.haml
@@ -0,0 +1,2 @@
+= render :partial => 'layouts/admin_nav'
+= render :partial => 'layouts/admin_content_tabs'
diff --git a/src/app/views/provider_realms/show.html.haml
b/src/app/views/provider_realms/show.html.haml
new file mode 100644
index 0000000..041b199
--- /dev/null
+++ b/src/app/views/provider_realms/show.html.haml
@@ -0,0 +1,17 @@
+= render :partial => 'layouts/admin_nav'
+%header.admin-page-header
+ %h1{:class => controller.controller_name}= @realm.name
+
+%section.admin-content-section.realm
+ %header
+ %h2= t'realms.show.properties'
+
+ .content
+ = render :partial => 'properties'
+
+%section.admin-content-section.realm_mapping
+ %header
+ %h2= t'realms.show.realm_mapping'
+
+ .content
+ = render :partial => 'mapping'
diff --git a/src/app/views/realms/_mapping.html.haml
b/src/app/views/realms/_mapping.html.haml
index a1ec09d..d5eced4 100644
--- a/src/app/views/realms/_mapping.html.haml
+++ b/src/app/views/realms/_mapping.html.haml
@@ -18,4 +18,4 @@
- @backend_realm_targets.each do |backend|
%tr{:class => cycle('nostripe','stripe')}
%td= check_box_tag "id[]", backend.id, :id =>
"backend_id_#{backend.id}"
- %td= backend.realm_or_provider.name
+ %td= "#{backend.target_provider.name}: #{backend.target_realm.name}"
diff --git a/src/config/routes.rb b/src/config/routes.rb
index 7127bdc..48c8e57 100644
--- a/src/config/routes.rb
+++ b/src/config/routes.rb
@@ -193,6 +193,10 @@ Conductor::Application.routes.draw do
post :filter, :on => :collection
end
+ resources :provider_realms do
+ post :filter, :on => :collection
+ end
+
resources :realm_mappings do
delete 'multi_destroy', :on => :collection
end
diff --git a/src/db/migrate/20120118221000_add_provider_accounts_realms.rb
b/src/db/migrate/20120118221000_add_provider_accounts_realms.rb
new file mode 100644
index 0000000..590e921
--- /dev/null
+++ b/src/db/migrate/20120118221000_add_provider_accounts_realms.rb
@@ -0,0 +1,38 @@
+#
+# Copyright 2012 Red Hat, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#
http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Filters added to this controller apply to all controllers in the application.
+# Likewise, all the methods added will be available for all controllers.
+
+class AddProviderAccountsRealms < ActiveRecord::Migration
+ def self.up
+ create_table :provider_accounts_realms, :id => false do |t|
+ t.integer :provider_account_id, :null => false
+ t.integer :realm_id, :null => false
+ end
+
+ Realm.transaction do
+ Realm.all.each do |realm|
+ realm.provider_accounts << realm.provider.provider_accounts
+ realm.save!
+ end
+ end
+ end
+
+ def self.down
+ drop_table :provider_accounts_realms
+ end
+end
diff --git a/src/spec/models/provider_account_spec.rb
b/src/spec/models/provider_account_spec.rb
index 7c1e60d..6a52224 100644
--- a/src/spec/models/provider_account_spec.rb
+++ b/src/spec/models/provider_account_spec.rb
@@ -73,7 +73,7 @@ describe ProviderAccount do
it "should fail to create a cloud account if fetching of realms fails" do
provider_account = Factory.build(:mock_provider_account)
provider_account.stub(:populate_realms).and_raise(ActiveRecord::RecordInvalid)
- provider_account.save.should == false
+ lambda {provider_account.save!}.should raise_exception
end
it "when calling connect and it fails with exception it will return nil" do
--
1.7.6.4