---
src/app/controllers/deployables_controller.rb | 1 +
src/app/models/base_permission_object.rb | 16 ++++++
src/app/models/catalog.rb | 19 ++++++-
src/app/models/catalog_entry.rb | 11 ++++-
src/app/models/deployable.rb | 8 ++-
src/app/models/deployment.rb | 14 +++++-
.../{permission.rb => derived_permission.rb} | 43 ++++++---------
src/app/models/hardware_profile.rb | 4 ++
src/app/models/instance.rb | 10 +++-
src/app/models/permission.rb | 32 +++++++++++
src/app/models/permissioned_object.rb | 51 ++++++++++++++++--
src/app/models/pool.rb | 16 +++++-
src/app/models/pool_family.rb | 21 +++++++
src/app/models/privilege.rb | 8 ++--
src/app/models/provider.rb | 12 ++++
src/app/models/provider_account.rb | 10 +++-
src/app/models/role.rb | 8 +++
src/app/models/user.rb | 1 +
.../20120424151000_create_derived_permissions.rb | 37 +++++++++++++
src/spec/models/deployable_spec.rb | 57 ++++++++++++++++++++
src/spec/models/deployment_spec.rb | 4 +-
src/spec/models/instance_observer_spec.rb | 1 +
22 files changed, 340 insertions(+), 44 deletions(-)
copy src/app/models/{permission.rb => derived_permission.rb} (75%)
create mode 100644 src/db/migrate/20120424151000_create_derived_permissions.rb
diff --git a/src/app/controllers/deployables_controller.rb
b/src/app/controllers/deployables_controller.rb
index 8967e79..911e337 100644
--- a/src/app/controllers/deployables_controller.rb
+++ b/src/app/controllers/deployables_controller.rb
@@ -191,6 +191,7 @@ class DeployablesController < ApplicationController
end
end
+ # the name here is confusing; we may want to rename to multi_remove at some point
def multi_destroy
deleted = []
not_deleted = []
diff --git a/src/app/models/base_permission_object.rb
b/src/app/models/base_permission_object.rb
index 8133a7f..ce25861 100644
--- a/src/app/models/base_permission_object.rb
+++ b/src/app/models/base_permission_object.rb
@@ -31,6 +31,9 @@ class BasePermissionObject < ActiveRecord::Base
has_many :permissions, :as => :permission_object, :dependent => :destroy,
:include => [:role],
:order => "permissions.id ASC"
+ has_many :derived_permissions, :as => :permission_object, :dependent =>
:destroy,
+ :include => [:role],
+ :order => "derived_permissions.id ASC"
validates_presence_of :name
validates_uniqueness_of :name
@@ -42,4 +45,17 @@ class BasePermissionObject < ActiveRecord::Base
base_permission = self.create!(:name => GENERAL_PERMISSION_SCOPE) unless
base_permission
base_permission
end
+
+ def derived_subtree(role = nil)
+ subtree = super(role)
+ [Catalog, Deployable, PoolFamily, Pool, Deployment,
+ Instance, Provider, ProviderAccount, HardwareProfile].each do |obj_type|
+ subtree += obj_type.all if (role.nil? or role.privilege_target_match(obj_type))
+ end
+ subtree
+ end
+ def self.additional_privilege_target_types
+ [HardwareProfile, Catalog, Deployable, PoolFamily, Pool,
+ Deployment, Instance, Provider, ProviderAccount]
+ end
end
diff --git a/src/app/models/catalog.rb b/src/app/models/catalog.rb
index 1f3ac9a..5ab51c4 100644
--- a/src/app/models/catalog.rb
+++ b/src/app/models/catalog.rb
@@ -38,18 +38,30 @@ class Catalog < ActiveRecord::Base
has_many :permissions, :as => :permission_object, :dependent => :destroy,
:include => [:role],
:order => "permissions.id ASC"
+ has_many :derived_permissions, :as => :permission_object, :dependent =>
:destroy,
+ :include => [:role],
+ :order => "derived_permissions.id ASC"
before_destroy :destroy_deployables_related_only_to_self
before_create :set_pool_family
+ after_update :update_deployable_permissions
validates_presence_of :pool
validates_presence_of :name
validates_uniqueness_of :name
validates_length_of :name, :maximum => 1024
- def object_list
+ def perm_ancestors
super + [pool, pool_family]
end
+ def derived_subtree(role = nil)
+ subtree = super(role)
+ subtree += deployables if (role.nil? or role.privilege_target_match(Deployable))
+ subtree
+ end
+ def self.additional_privilege_target_types
+ [Deployable]
+ end
class << self
alias orig_list_for_user_include list_for_user_include
alias orig_list_for_user_conditions list_for_user_conditions
@@ -80,6 +92,11 @@ class Catalog < ActiveRecord::Base
self[:pool_family_id] = pool.pool_family_id
end
+ def update_deployable_permissions
+ update_derived_permissions_for_ancestors
+ deployables.each {|d| d.update_derived_permissions_for_ancestors}
+ end
+
private
def self.apply_search_filter(search)
diff --git a/src/app/models/catalog_entry.rb b/src/app/models/catalog_entry.rb
index 857d013..03461d2 100644
--- a/src/app/models/catalog_entry.rb
+++ b/src/app/models/catalog_entry.rb
@@ -36,9 +36,18 @@ class CatalogEntry < ActiveRecord::Base
validates_uniqueness_of :catalog_id, :scope => [:deployable_id]
after_destroy :destroy_deployable_if_last
+ after_create :update_deployable_permissions
+
+ def update_deployable_permissions
+ deployable.update_derived_permissions_for_ancestors
+ end
def destroy_deployable_if_last
- deployable.destroy if deployable.catalog_entries.blank?
+ if deployable.catalog_entries.blank?
+ deployable.destroy
+ else
+ deployable.update_derived_permissions_for_ancestors
+ end
end
# This probably goes away once we separate catalog entry creation from deployables
diff --git a/src/app/models/deployable.rb b/src/app/models/deployable.rb
index 5f4157e..02c53ff 100644
--- a/src/app/models/deployable.rb
+++ b/src/app/models/deployable.rb
@@ -34,6 +34,10 @@ class Deployable < ActiveRecord::Base
has_many :permissions, :as => :permission_object, :dependent => :destroy,
:include => [:role],
:order => "permissions.id ASC"
+ has_many :derived_permissions, :as => :permission_object, :dependent =>
:destroy,
+ :include => [:role],
+ :order => "derived_permissions.id ASC"
+
has_many :catalog_entries, :dependent => :destroy
has_many :catalogs, :through => :catalog_entries
belongs_to :pool_family
@@ -49,8 +53,8 @@ class Deployable < ActiveRecord::Base
PRESET_FILTERS_OPTIONS = []
- def object_list
- super + catalogs + catalogs.collect{|c| c.pool} + [pool_family]
+ def perm_ancestors
+ super + catalogs + catalogs.collect{|c| c.pool}.uniq + [pool_family]
end
class << self
alias orig_list_for_user_include list_for_user_include
diff --git a/src/app/models/deployment.rb b/src/app/models/deployment.rb
index 4ad2082..559f027 100644
--- a/src/app/models/deployment.rb
+++ b/src/app/models/deployment.rb
@@ -52,6 +52,10 @@ class Deployment < ActiveRecord::Base
has_many :permissions, :as => :permission_object, :dependent => :destroy,
:include => [:role],
:order => "permissions.id ASC"
+ has_many :derived_permissions, :as => :permission_object, :dependent =>
:destroy,
+ :include => [:role],
+ :order => "derived_permissions.id ASC"
+
belongs_to :owner, :class_name => "User", :foreign_key =>
"owner_id"
has_many :events, :as => :source, :dependent => :destroy
@@ -118,9 +122,17 @@ class Deployment < ActiveRecord::Base
errors.add(:pool, I18n.t('pools.errors.providers_disabled')) if pool and
pool.pool_family.all_providers_disabled?
end
- def object_list
+ def perm_ancestors
super + [pool, pool_family]
end
+ def derived_subtree(role = nil)
+ subtree = super(role)
+ subtree += instances if (role.nil? or role.privilege_target_match(Instance))
+ subtree
+ end
+ def self.additional_privilege_target_types
+ [Instance]
+ end
class << self
alias orig_list_for_user_include list_for_user_include
alias orig_list_for_user_conditions list_for_user_conditions
diff --git a/src/app/models/permission.rb b/src/app/models/derived_permission.rb
similarity index 75%
copy from src/app/models/permission.rb
copy to src/app/models/derived_permission.rb
index ccda5f7..06e7e8e 100644
--- a/src/app/models/permission.rb
+++ b/src/app/models/derived_permission.rb
@@ -14,32 +14,12 @@
# limitations under the License.
#
-# == Schema Information
-# Schema version: 20110207110131
-#
-# Table name: permissions
-#
-# id :integer not null, primary key
-# role_id :integer not null
-# user_id :integer not null
-# permission_object_id :integer
-# permission_object_type :string(255)
-# lock_version :integer default(0)
-# created_at :datetime
-# updated_at :datetime
-#
-
-class Permission < ActiveRecord::Base
- belongs_to :role
- belongs_to :user
-
- validates_presence_of :role_id
-
- validates_presence_of :user_id
- validates_uniqueness_of :user_id, :scope => [:permission_object_id,
- :permission_object_type,
- :role_id]
+class DerivedPermission < ActiveRecord::Base
+ # the source permission for the denormalized object
+ belongs_to :permission
+ validates_presence_of :permission_id
+ # this is the object used for permission checks
belongs_to :permission_object, :polymorphic => true
# type-specific associations
belongs_to :pool_family, :class_name => "PoolFamily",
@@ -58,7 +38,20 @@ class Permission < ActiveRecord::Base
:foreign_key =>
"permission_object_id"
belongs_to :provider_account, :class_name => "ProviderAccount",
:foreign_key =>
"permission_object_id"
+ belongs_to :hardware_profile, :class_name => "hardwareProfile",
+ :foreign_key =>
"permission_object_id"
belongs_to :base_permission_object, :class_name =>
"BasePermissionObject",
:foreign_key =>
"permission_object_id"
+ # role is copied from source permission
+ belongs_to :role
+ validates_presence_of :role_id
+
+ # user is copied from source permission
+ belongs_to :user
+ validates_presence_of :user_id
+
+ validates_uniqueness_of :permission_id, :scope => [:permission_object_id,
+ :permission_object_type]
+
end
diff --git a/src/app/models/hardware_profile.rb b/src/app/models/hardware_profile.rb
index 9c325c1..2099214 100644
--- a/src/app/models/hardware_profile.rb
+++ b/src/app/models/hardware_profile.rb
@@ -41,6 +41,10 @@ class HardwareProfile < ActiveRecord::Base
end
include PermissionedObject
has_many :permissions, :as => :permission_object, :dependent => :destroy
+ has_many :derived_permissions, :as => :permission_object, :dependent =>
:destroy,
+ :include => [:role],
+ :order => "derived_permissions.id ASC"
+
has_many :instances
scope :frontend, :conditions => { :provider_id => nil }
has_many :provider_instances, :class_name => "Instance",
diff --git a/src/app/models/instance.rb b/src/app/models/instance.rb
index 062372e..84f1224 100644
--- a/src/app/models/instance.rb
+++ b/src/app/models/instance.rb
@@ -80,6 +80,10 @@ class Instance < ActiveRecord::Base
has_many :permissions, :as => :permission_object, :dependent => :destroy,
:include => [:role],
:order => "permissions.id ASC"
+ has_many :derived_permissions, :as => :permission_object, :dependent =>
:destroy,
+ :include => [:role],
+ :order => "derived_permissions.id ASC"
+
has_many :events, :as => :source, :dependent => :destroy
has_many :instance_parameters, :dependent => :destroy
has_many :tasks, :as =>:task_target, :dependent => :destroy
@@ -141,8 +145,10 @@ class Instance < ActiveRecord::Base
# changed if called from another Aeolus component, so attr_protected isn't quite
what we want:
USER_MUTABLE_ATTRS = ['name']
- def object_list
- super + [deployment, pool, pool_family]
+ def perm_ancestors
+ ancestors = super
+ ancestors << deployment unless deployment.nil?
+ ancestors += [pool, pool_family]
end
class << self
alias orig_list_for_user_include list_for_user_include
diff --git a/src/app/models/permission.rb b/src/app/models/permission.rb
index ccda5f7..89b2268 100644
--- a/src/app/models/permission.rb
+++ b/src/app/models/permission.rb
@@ -58,7 +58,39 @@ class Permission < ActiveRecord::Base
:foreign_key =>
"permission_object_id"
belongs_to :provider_account, :class_name => "ProviderAccount",
:foreign_key =>
"permission_object_id"
+ belongs_to :hardware_profile, :class_name => "hardwareProfile",
+ :foreign_key =>
"permission_object_id"
belongs_to :base_permission_object, :class_name =>
"BasePermissionObject",
:foreign_key =>
"permission_object_id"
+ has_many :derived_permissions, :dependent => :destroy
+
+ after_save :update_derived_permissions
+
+ def update_derived_permissions
+ new_derived_permission_objects = permission_object.derived_subtree(role)
+ old_derived_permissions = derived_permissions
+ old_derived_permissions.each do |derived_perm|
+ if new_derived_permission_objects.delete(derived_perm.permission_object)
+ # object is in both old and new list -- update as necessary
+ derived_perm.role = role
+ derived_perm.user_id = user_id
+ derived_perm.save!
+ else
+ # object is in old but not new list -- remove it
+ derived_perm.destroy
+ end
+ end
+ new_derived_permission_objects.each do |perm_obj|
+ unless DerivedPermission.where(:permission_id => id,
+ :permission_object_id => perm_obj.id,
+ :permission_object_type =>
perm_obj.class.name).any?
+ derived_perm = DerivedPermission.new(:user_id => user_id,
+ :role_id => role_id,
+ :permission_object => perm_obj,
+ :permission => self)
+ derived_perm.save!
+ end
+ end
+ end
end
diff --git a/src/app/models/permissioned_object.rb
b/src/app/models/permissioned_object.rb
index c534261..3f083ea 100644
--- a/src/app/models/permissioned_object.rb
+++ b/src/app/models/permissioned_object.rb
@@ -19,7 +19,7 @@ module PermissionedObject
def has_privilege(user, action, target_type=nil)
return false if user.nil? or action.nil?
target_type = self.class.default_privilege_target_type if target_type.nil?
- object_list.each do |obj|
+ perm_ancestors.each do |obj|
return true if obj and obj.permissions.find(:first,
:include => [:role => :privileges],
:conditions =>
@@ -35,10 +35,39 @@ module PermissionedObject
# Returns the list of objects to check for permissions on -- by default
# this object plus the Base permission object
- def object_list
+ # At the moment, the retuned list is not necessarily ordered
+ # FIXME: remove self once has_privilege stops using this method
+ def perm_ancestors
[self, BasePermissionObject.general_permission_scope]
end
-
+ # Returns the list of objects to generate derived permissions for
+ # -- by default just this object
+ def derived_subtree(role = nil)
+ [self]
+ end
+ # on obj creation, set inherited permissions for new object
+ def update_derived_permissions_for_ancestors
+ # for create hook this should normally be empty
+ old_derived_permissions = Hash[derived_permissions.map{|p| [p.permission.id,p]}]
+ perm_ancestors.each do |perm_obj|
+ perm_obj.permissions.each do |permission|
+ if
permission.role.privilege_target_match(self.class.default_privilege_target_type)
+ unless old_derived_permissions.delete(permission.id)
+ derived_permissions.create(:user_id => permission.user_id,
+ :role_id => permission.role_id,
+ :permission => permission)
+ end
+ end
+ end
+ end
+ # anything remaining in old_derived_permissions should be removed,
+ # as would be expected if this hook is triggered by removing a
+ # catalog entry for a deployable
+ old_derived_permissions.each do |id, derived_perm|
+ derived_perm.destroy
+ end
+ #reload
+ end
# assign owner role so that the creating user has permissions on the object
# Any roles defined on default_privilege_target_type with assign_to_owner==true
# will be assigned to the passed-in user on this object
@@ -49,14 +78,28 @@ module PermissionedObject
roles.each do |role|
Permission.create!(:role => role, :user => user, :permission_object =>
self)
end
+ self.reload
end
# Any methods here will be able to use the context of the
# ActiveRecord model the module is included in.
def self.included(base)
base.class_eval do
+ after_create :update_derived_permissions_for_ancestors
+
+ # Returns the list of privilege target types that are relevant for
+ # permission checking purposes. This is used in setting derived
+ # permissions -- there's no need to create denormalized permissions
+ # for a role which only grants Provider privileges on a Pool
+ # object. By default, this is just the current object's type
+ def self.active_privilege_target_types
+ [self.default_privilege_target_type] + self.additional_privilege_target_types
+ end
+ def self.additional_privilege_target_types
+ []
+ end
def self.default_privilege_target_type
- self.name.constantize
+ self
end
def self.list_for_user_include
[:permissions]
diff --git a/src/app/models/pool.rb b/src/app/models/pool.rb
index 4604bd2..9110481 100644
--- a/src/app/models/pool.rb
+++ b/src/app/models/pool.rb
@@ -60,6 +60,9 @@ class Pool < ActiveRecord::Base
has_many :permissions, :as => :permission_object, :dependent => :destroy,
:include => [:role],
:order => "permissions.id ASC"
+ has_many :derived_permissions, :as => :permission_object, :dependent =>
:destroy,
+ :include => [:role],
+ :order => "derived_permissions.id ASC"
has_many :deployments, :dependent => :destroy
@@ -148,9 +151,20 @@ class Pool < ActiveRecord::Base
{:title => "pools.preset_filters.with_stopped_instances", :id =>
"with_stopped_instances", :query => includes(:deployments =>
:instances).where("instances.state" => "stopped")}
]
- def object_list
+ def perm_ancestors
super + [pool_family]
end
+ def derived_subtree(role = nil)
+ subtree = super(role)
+ subtree += deployments if (role.nil? or role.privilege_target_match(Deployment))
+ subtree += instances if (role.nil? or role.privilege_target_match(Instance))
+ subtree += catalogs if (role.nil? or role.privilege_target_match(Deployable))
+ subtree += catalogs.collect {|c| c.deployables}.flatten.uniq if (role.nil? or
role.privilege_target_match(Deployable))
+ subtree
+ end
+ def self.additional_privilege_target_types
+ [Deployment, Instance, Catalog, Quota]
+ end
class << self
alias orig_list_for_user_include list_for_user_include
alias orig_list_for_user_conditions list_for_user_conditions
diff --git a/src/app/models/pool_family.rb b/src/app/models/pool_family.rb
index dd474a9..60fb0cb 100644
--- a/src/app/models/pool_family.rb
+++ b/src/app/models/pool_family.rb
@@ -43,6 +43,14 @@ class PoolFamily < ActiveRecord::Base
accepts_nested_attributes_for :quota
has_and_belongs_to_many :provider_accounts, :uniq => true, :order =>
"provider_accounts.priority asc"
has_many :permissions, :as => :permission_object, :dependent => :destroy
+ has_many :derived_permissions, :as => :permission_object, :dependent =>
:destroy,
+ :include => [:role],
+ :order => "derived_permissions.id ASC"
+
+ has_many :catalogs
+ has_many :deployables
+ has_many :instances
+ has_many :deployments
validates_length_of :name, :maximum => 255
validates_format_of :name, :with => /^[\w -]*$/n, :message => "must only
contain: numbers, letters, spaces, '_' and '-'"
@@ -61,6 +69,19 @@ class PoolFamily < ActiveRecord::Base
MetadataObject.set(DEFAULT_POOL_FAMILY_KEY, self)
end
+ def derived_subtree(role = nil)
+ subtree = super(role)
+ subtree += pools if (role.nil? or role.privilege_target_match(Pool))
+ subtree += deployments if (role.nil? or role.privilege_target_match(Deployment))
+ subtree += instances if (role.nil? or role.privilege_target_match(Instance))
+ subtree += catalogs if (role.nil? or role.privilege_target_match(Deployable))
+ subtree += deployables if (role.nil? or role.privilege_target_match(Deployable))
+ subtree
+ end
+ def self.additional_privilege_target_types
+ [Pool, Quota]
+ end
+
def destroyable?
# A PoolFamily is destroyable if its pools are destroyable and it is not the default
PoolFamily
pools.all? {|p| p.destroyable? } && self != PoolFamily.default
diff --git a/src/app/models/privilege.rb b/src/app/models/privilege.rb
index ae1f038..1d857db 100644
--- a/src/app/models/privilege.rb
+++ b/src/app/models/privilege.rb
@@ -51,14 +51,14 @@ class Privilege < ActiveRecord::Base
PERM_SET, PERM_VIEW]
TYPES = { BasePermissionObject => [MODIFY, PERM_SET, PERM_VIEW],
Pool => ACTIONS - [USE],
- PoolFamily => ACTIONS - [USE],
+ PoolFamily => ACTIONS,
Instance => ACTIONS,
Deployment => ACTIONS,
- CatalogEntry => ACTIONS,
+ Deployable => ACTIONS,
Quota => [VIEW, MODIFY],
- HardwareProfile => ACTIONS - [USE, VIEW],
+ HardwareProfile => ACTIONS - [USE],
Realm => ACTIONS - [VIEW],
- Provider => ACTIONS - [USE],
+ Provider => ACTIONS,
ProviderAccount => ACTIONS,
User => [ CREATE, MODIFY, VIEW] }
diff --git a/src/app/models/provider.rb b/src/app/models/provider.rb
index 2033a04..e1fb385 100644
--- a/src/app/models/provider.rb
+++ b/src/app/models/provider.rb
@@ -56,9 +56,21 @@ class Provider < ActiveRecord::Base
has_many :permissions, :as => :permission_object, :dependent => :destroy,
:include => [:role],
:order => "permissions.id ASC"
+ has_many :derived_permissions, :as => :permission_object, :dependent =>
:destroy,
+ :include => [:role],
+ :order => "derived_permissions.id ASC"
before_destroy :destroyable?
+ def derived_subtree(role = nil)
+ subtree = super(role)
+ subtree += provider_accounts if (role.nil? or
role.privilege_target_match(ProviderAccount))
+ subtree
+ end
+ def self.additional_privilege_target_types
+ [ProviderAccount]
+ end
+
scope :enabled, where("enabled = ?", true)
def encoded_url_with_driver_and_provider
diff --git a/src/app/models/provider_account.rb b/src/app/models/provider_account.rb
index 232928e..0ebc848 100644
--- a/src/app/models/provider_account.rb
+++ b/src/app/models/provider_account.rb
@@ -48,6 +48,9 @@ class ProviderAccount < ActiveRecord::Base
has_many :permissions, :as => :permission_object, :dependent => :destroy,
:include => [:role],
:order => "permissions.id ASC"
+ has_many :derived_permissions, :as => :permission_object, :dependent =>
:destroy,
+ :include => [:role],
+ :order => "derived_permissions.id ASC"
# validation of credentials is done in provider_account validation, :validate =>
false prevents nested_attributes from validation
has_many :credentials, :dependent => :destroy, :validate => false
@@ -106,8 +109,11 @@ class ProviderAccount < ActiveRecord::Base
return true
end
- def object_list
- super << provider
+ def perm_ancestors
+ super + [provider]
+ end
+ def self.additional_privilege_target_types
+ [Quota]
end
class << self
alias orig_list_for_user_include list_for_user_include
diff --git a/src/app/models/role.rb b/src/app/models/role.rb
index 98f0a5a..dcf3178 100644
--- a/src/app/models/role.rb
+++ b/src/app/models/role.rb
@@ -30,6 +30,7 @@
class Role < ActiveRecord::Base
has_many :permissions, :dependent => :destroy
+ has_many :derived_permissions, :dependent => :destroy
has_many :privileges, :dependent => :destroy
validates_presence_of :scope
@@ -39,4 +40,11 @@ class Role < ActiveRecord::Base
validates_associated :privileges
validates_length_of :name, :maximum => 255
+
+ def privilege_target_types
+ privileges.collect {|x| Kernel.const_get(x.target_type)}.uniq
+ end
+ def privilege_target_match(obj_type)
+ (privilege_target_types & obj_type.active_privilege_target_types).any?
+ end
end
diff --git a/src/app/models/user.rb b/src/app/models/user.rb
index c2822ea..66565a7 100644
--- a/src/app/models/user.rb
+++ b/src/app/models/user.rb
@@ -59,6 +59,7 @@ class User < ActiveRecord::Base
attr_accessor :ignore_password
has_many :permissions, :dependent => :destroy
+ has_many :derived_permissions, :dependent => :destroy
has_many :owned_instances, :class_name => "Instance", :foreign_key =>
"owner_id"
has_many :deployments, :foreign_key => "owner_id"
has_many :view_states
diff --git a/src/db/migrate/20120424151000_create_derived_permissions.rb
b/src/db/migrate/20120424151000_create_derived_permissions.rb
new file mode 100644
index 0000000..318d320
--- /dev/null
+++ b/src/db/migrate/20120424151000_create_derived_permissions.rb
@@ -0,0 +1,37 @@
+#
+# 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 CreateDerivedPermissions < ActiveRecord::Migration
+ def self.up
+ create_table :derived_permissions do |t|
+ t.integer :permission_id, :null => false
+ t.integer :role_id, :null => false
+ t.integer :user_id, :null => false
+ t.integer :permission_object_id
+ t.string :permission_object_type
+ t.integer :lock_version, :default => 0
+
+ t.timestamps
+ end
+ # create derived permissions for existing records
+ Permission.all.each do |permission|
+ permission.update_derived_permissions
+ end
+ end
+
+ def self.down
+ drop_table :derived_permissions
+ end
+end
diff --git a/src/spec/models/deployable_spec.rb b/src/spec/models/deployable_spec.rb
index 6b32968..a98eed7 100644
--- a/src/spec/models/deployable_spec.rb
+++ b/src/spec/models/deployable_spec.rb
@@ -71,4 +71,61 @@ describe Deployable do
deployable.xml = ''
deployable.should_not be_valid
end
+
+ it "should manage permissions on catalog changes" do
+ pool1 = FactoryGirl.create :pool
+ pool2 = FactoryGirl.create :pool
+ catalog1 = FactoryGirl.create :catalog #, :pool => :pool1
+ catalog2 = FactoryGirl.create :catalog
+ catalog1.pool.should_not == catalog2.pool
+ admin = FactoryGirl.create :admin_user
+ pool1_perm = Permission.create(:user => admin,
+ :role => Role.first(:conditions =>
+ ['name = ?',
'pool.admin']),
+ :permission_object => catalog1.pool)
+ pool2_perm = Permission.create(:user => admin,
+ :role => Role.first(:conditions =>
+ ['name = ?',
'pool.deployable.admin']),
+ :permission_object => catalog2.pool)
+ deployable = FactoryGirl.create :deployable, :catalogs => [catalog1]
+ catalog1.reload
+ catalog2.reload
+ catalog1.pool.permissions.should == [pool1_perm]
+ catalog2.pool.permissions.should == [pool2_perm]
+
+ catalog1.derived_permissions.collect {|p|
+ p.role.name}.should == ["pool.admin"]
+ catalog2.derived_permissions.collect {|p|
+ p.role.name}.should == ["pool.deployable.admin"]
+ deployable.derived_permissions.collect {|p|
+ p.role.name}.include?("pool.admin").should be_true
+ deployable.derived_permissions.collect {|p|
+ p.role.name}.include?("pool.deployable.admin").should be_false
+ deployable.catalogs.should == [catalog1]
+
+ deployable.catalogs << catalog2
+ deployable.reload
+ deployable.catalogs.should == [catalog1, catalog2]
+ deployable.derived_permissions.collect {|p|
+ p.role.name}.include?("pool.admin").should be_true
+ deployable.derived_permissions.collect {|p|
+ p.role.name}.include?("pool.deployable.admin").should be_true
+
+ deployable.catalog_entries.where(:catalog_id => catalog1.id).first.destroy
+ deployable.reload
+ deployable.catalogs.should == [catalog2]
+ deployable.derived_permissions.collect {|p|
+ p.role.name}.include?("pool.admin").should be_false
+ deployable.derived_permissions.collect {|p|
+ p.role.name}.include?("pool.deployable.admin").should be_true
+
+ catalog2.pool = catalog1.pool
+ catalog2.save
+ deployable.reload
+ deployable.catalogs.should == [catalog2]
+ deployable.derived_permissions.collect {|p|
+ p.role.name}.include?("pool.admin").should be_true
+ deployable.derived_permissions.collect {|p|
+ p.role.name}.include?("pool.deployable.admin").should be_false
+ end
end
diff --git a/src/spec/models/deployment_spec.rb b/src/spec/models/deployment_spec.rb
index f382eda..7706345 100644
--- a/src/spec/models/deployment_spec.rb
+++ b/src/spec/models/deployment_spec.rb
@@ -96,7 +96,7 @@ describe Deployment do
@deployment.save!
inst1 = Factory.create :mock_running_instance, :deployment_id => @deployment.id
inst2 = Factory.create :mock_running_instance, :deployment_id => @deployment.id
-
+ @deployment.reload
@deployment.should_not be_destroyable
@deployment.destroy.should == false
@@ -117,6 +117,7 @@ describe Deployment do
inst2.state = Instance::STATE_STOPPED
inst2.save!
inst3 = Factory.create :mock_running_instance, :deployment_id => @deployment.id
+ @deployment.reload
Taskomatic.stub!(:stop_instance).and_return(nil)
@deployment.stop_instances_and_destroy!
inst1.tasks.last.action.should == 'stop'
@@ -297,6 +298,7 @@ describe Deployment do
@deployment.save!
inst1 = Factory.create :mock_running_instance, :deployment_id => @deployment.id
inst2 = Factory.create :mock_running_instance, :deployment_id => @deployment.id
+ @deployment.reload
@deployment.stop_instances_and_destroy!
diff --git a/src/spec/models/instance_observer_spec.rb
b/src/spec/models/instance_observer_spec.rb
index d014077..9cc70be 100644
--- a/src/spec/models/instance_observer_spec.rb
+++ b/src/spec/models/instance_observer_spec.rb
@@ -209,6 +209,7 @@ describe InstanceObserver do
it "should destroy the instance key when the instance is stopped" do
@instance = FactoryGirl.create :mock_running_instance
+ @instance_key = FactoryGirl.create :mock_instance_key, :instance => @instance
@instance.instance_key.should_not be_nil
@instance.state = Instance::STATE_STOPPED
@instance.save!
--
1.7.6.5