ACK. This works fine for me (once I remembered to restart tasko and db-omatic). Not that I could not test the lvm change, as I do not have lvm currently in my test deployment.<br><br><div class="gmail_quote">On Tue, May 19, 2009 at 10:23 AM, Scott Seago <span dir="ltr"><<a href="mailto:sseago@redhat.com">sseago@redhat.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"><br>
Signed-off-by: Scott Seago <<a href="mailto:sseago@redhat.com">sseago@redhat.com</a>><br>
---<br>
src/app/controllers/storage_volume_controller.rb | 164 +++++-----------------<br>
src/app/models/lvm_storage_volume.rb | 8 +<br>
src/app/services/storage_volume_service.rb | 145 +++++++++++++++++++<br>
3 files changed, 187 insertions(+), 130 deletions(-)<br>
create mode 100644 src/app/services/storage_volume_service.rb<br>
<br>
diff --git a/src/app/controllers/storage_volume_controller.rb b/src/app/controllers/storage_volume_controller.rb<br>
index 6bdbbdc..b87f9b6 100644<br>
--- a/src/app/controllers/storage_volume_controller.rb<br>
+++ b/src/app/controllers/storage_volume_controller.rb<br>
@@ -18,156 +18,60 @@<br>
# also available at <a href="http://www.gnu.org/copyleft/gpl.html" target="_blank">http://www.gnu.org/copyleft/gpl.html</a>.<br>
<br>
class StorageVolumeController < ApplicationController<br>
+ include StorageVolumeService<br>
<br>
def new<br>
+ svc_new(params[:storage_pool_id], params[:source_volume_id])<br>
@return_to_workflow = params[:return_to_workflow] || false<br>
- if params[:storage_pool_id]<br>
- unless @storage_pool.user_subdividable<br>
- html_error_page("User-created storage volumes are not supported on this pool")<br>
- return<br>
- end<br>
- @storage_volume = StorageVolume.factory(@storage_pool.get_type_label,<br>
- { :storage_pool_id =><br>
- params[:storage_pool_id]})<br>
- else<br>
- unless @source_volume.supports_lvm_subdivision<br>
- html_error_page("LVM is not supported for this storage volume")<br>
- return<br>
- end<br>
- lvm_pool = @source_volume.lvm_storage_pool<br>
- unless lvm_pool<br>
- # FIXME: what should we do about VG/LV names?<br>
- # for now auto-create VG name as ovirt_vg_#{@<a href="http://source_volume.id" target="_blank">source_volume.id</a>}<br>
- new_params = { :vg_name => "ovirt_vg_#{@<a href="http://source_volume.id" target="_blank">source_volume.id</a>}",<br>
- :hardware_pool_id => @source_volume.storage_pool.hardware_pool_id}<br>
- lvm_pool = StoragePool.factory(StoragePool::LVM, new_params)<br>
- lvm_pool.source_volumes << @source_volume<br>
- lvm_pool.save!<br>
- end<br>
- @storage_volume = StorageVolume.factory(lvm_pool.get_type_label,<br>
- { :storage_pool_id => <a href="http://lvm_pool.id" target="_blank">lvm_pool.id</a>})<br>
- @storage_volume.lv_owner_perms='0744'<br>
- @storage_volume.lv_group_perms='0744'<br>
- @storage_volume.lv_mode_perms='0744'<br>
- end<br>
render :layout => 'popup'<br>
end<br>
<br>
def create<br>
- begin<br>
- StorageVolume.transaction do<br>
- @storage_volume.save!<br>
- @task = StorageVolumeTask.new({ :user => @user,<br>
- :task_target => @storage_volume,<br>
- :action => StorageVolumeTask::ACTION_CREATE_VOLUME,<br>
- :state => Task::STATE_QUEUED})<br>
- @task.save!<br>
- end<br>
- respond_to do |format|<br>
- format.json { render :json => { :object => "storage_volume",<br>
- :success => true,<br>
- :alert => "Storage Volume was successfully created." ,<br>
- :new_volume => @storage_volume.storage_tree_element({:filter_unavailable => false, :state => 'new'})} }<br>
- format.xml { render :xml => @storage_volume,<br>
- :status => :created,<br>
- # FIXME: create storage_volume_url method if relevant<br>
- :location => storage_pool_url(@storage_volume)<br>
- }<br>
- end<br>
- rescue => ex<br>
- # FIXME: need to distinguish volume vs. task save errors<br>
- respond_to do |format|<br>
- format.json {<br>
- json_hash = { :object => "storage_volume", :success => false,<br>
- :errors => @storage_volume.errors.localize_error_messages.to_a }<br>
- json_hash[:message] = ex.message if json_hash[:errors].empty?<br>
- render :json => json_hash }<br>
- format.xml { render :xml => @storage_volume.errors,<br>
- :status => :unprocessable_entity }<br>
- end<br>
+ volume = params[:storage_volume]<br>
+ unless type = params[:storage_type]<br>
+ type = volume.delete(:storage_type)<br>
+ end<br>
+ alert = svc_create(type, volume)<br>
+ respond_to do |format|<br>
+ format.json { render :json => { :object => "storage_volume",<br>
+ :success => true, :alert => alert,<br>
+ :new_volume => @storage_volume.storage_tree_element(<br>
+ {:filter_unavailable => false, :state => 'new'})} }<br>
+ format.xml { render :xml => @storage_volume,<br>
+ :status => :created,<br>
+ :location => storage_pool_url(@storage_volume)<br>
+ }<br>
end<br>
end<br>
<br>
def show<br>
- @storage_volume = StorageVolume.find(params[:id])<br>
- set_perms(@storage_volume.storage_pool.hardware_pool)<br>
- @storage_pool = @storage_volume.storage_pool<br>
- if authorize_view<br>
- respond_to do |format|<br>
- format.html { render :layout => 'selection' }<br>
- format.json do<br>
- attr_list = []<br>
- attr_list << :id if (@storage_pool.user_subdividable and authorized?(Privilege::MODIFY))<br>
- attr_list += [:display_name, :size_in_gb, :get_type_label]<br>
- json_list(@storage_pool.storage_volumes, attr_list)<br>
- end<br>
- format.xml { render :xml => @storage_volume.to_xml }<br>
+ svc_show(params[:id])<br>
+ respond_to do |format|<br>
+ format.html { render :layout => 'selection' }<br>
+ format.json do<br>
+ attr_list = []<br>
+ attr_list << :id if (@storage_pool.user_subdividable and authorized?(Privilege::MODIFY))<br>
+ attr_list += [:display_name, :size_in_gb, :get_type_label]<br>
+ json_list(@storage_pool.storage_volumes, attr_list)<br>
end<br>
+ format.xml { render :xml => @storage_volume.to_xml }<br>
end<br>
end<br>
<br>
def destroy<br>
- unless authorized?(Privilege::MODIFY) and @storage_volume.storage_pool.user_subdividable<br>
- handle_error(:message =><br>
- "You do not have permission to delete this storage volume.",<br>
- :status => :forbidden,<br>
- :title => "Access Denied")<br>
- else<br>
- alert, success = delete_volume_internal(@storage_volume)<br>
- respond_to do |format|<br>
- format.json { render :json => { :object => "storage_volume",<br>
- :success => success, :alert => alert } }<br>
- format.xml { head(success ? :ok : :method_not_allowed) }<br>
- end<br>
+ alert = svc_destroy(params[:id])<br>
+ respond_to do |format|<br>
+ format.json { render :json => { :object => "storage_volume",<br>
+ :success => true, :alert => alert } }<br>
+ format.xml { head(:ok) }<br>
end<br>
end<br>
<br>
- def pre_new<br>
- if params[:storage_pool_id]<br>
- @storage_pool = StoragePool.find(params[:storage_pool_id])<br>
- set_perms(@storage_pool.hardware_pool)<br>
- else<br>
- @source_volume = StorageVolume.find(params[:source_volume_id])<br>
- set_perms(@source_volume.storage_pool.hardware_pool)<br>
- end<br>
+ # FIXME: remove these when service transition is complete. these are here<br>
+ # to keep from running permissions checks and other setup steps twice<br>
+ def tmp_pre_update<br>
end<br>
-<br>
- def pre_create<br>
- volume = params[:storage_volume]<br>
- unless type = params[:storage_type]<br>
- type = volume.delete(:storage_type)<br>
- end<br>
- @storage_volume = StorageVolume.factory(type, volume)<br>
- set_perms(@storage_volume.storage_pool.hardware_pool)<br>
- authorize_admin<br>
- end<br>
- # will go away w/ svc layer<br>
- def pre_edit<br>
- @storage_volume = StorageVolume.find(params[:id])<br>
- set_perms(@storage_volume.storage_pool.hardware_pool)<br>
- end<br>
-<br>
- private<br>
- def delete_volume_internal(volume)<br>
- begin<br>
- name = volume.display_name<br>
- if !volume.vms.empty?<br>
- vm_list = volume.vms.collect {|vm| vm.description}.join(", ")<br>
- ["Storage Volume #{name} must be unattached from VMs (#{vm_list}) before deleting it.",<br>
- false]<br>
- else<br>
- volume.state=StorageVolume::STATE_PENDING_DELETION<br>
- volume.save!<br>
- @task = StorageVolumeTask.new({ :user => @user,<br>
- :task_target => volume,<br>
- :action => StorageVolumeTask::ACTION_DELETE_VOLUME,<br>
- :state => Task::STATE_QUEUED})<br>
- @task.save!<br>
- ["Storage Volume #{name} deletion was successfully queued.", true]<br>
- end<br>
- rescue => ex<br>
- ["Failed to delete storage volume #{name} (#{ex.message}.",false]<br>
- end<br>
+ def tmp_authorize_admin<br>
end<br>
<br>
end<br>
diff --git a/src/app/models/lvm_storage_volume.rb b/src/app/models/lvm_storage_volume.rb<br>
index 5b6177b..8fd1bac 100644<br>
--- a/src/app/models/lvm_storage_volume.rb<br>
+++ b/src/app/models/lvm_storage_volume.rb<br>
@@ -18,6 +18,14 @@<br>
# also available at <a href="http://www.gnu.org/copyleft/gpl.html" target="_blank">http://www.gnu.org/copyleft/gpl.html</a>.<br>
<br>
class LvmStorageVolume < StorageVolume<br>
+<br>
+ def initialize(params)<br>
+ super<br>
+ self.lv_owner_perms='0744' unless self.lv_owner_perms<br>
+ self.lv_group_perms='0744' unless self.lv_group_perms<br>
+ self.lv_mode_perms='0744' unless self.lv_mode_perms<br>
+ end<br>
+<br>
def display_name<br>
"#{get_type_label}: #{storage_pool.vg_name}:#{lv_name}"<br>
end<br>
diff --git a/src/app/services/storage_volume_service.rb b/src/app/services/storage_volume_service.rb<br>
new file mode 100644<br>
index 0000000..6d338a5<br>
--- /dev/null<br>
+++ b/src/app/services/storage_volume_service.rb<br>
@@ -0,0 +1,145 @@<br>
+#<br>
+# Copyright (C) 2009 Red Hat, Inc.<br>
+# Written by Scott Seago <<a href="mailto:sseago@redhat.com">sseago@redhat.com</a>>,<br>
+#<br>
+# This program is free software; you can redistribute it and/or modify<br>
+# it under the terms of the GNU General Public License as published by<br>
+# the Free Software Foundation; version 2 of the License.<br>
+#<br>
+# This program is distributed in the hope that it will be useful,<br>
+# but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the<br>
+# GNU General Public License for more details.<br>
+#<br>
+# You should have received a copy of the GNU General Public License<br>
+# along with this program; if not, write to the Free Software<br>
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,<br>
+# MA 02110-1301, USA. A copy of the GNU General Public License is<br>
+# also available at <a href="http://www.gnu.org/copyleft/gpl.html" target="_blank">http://www.gnu.org/copyleft/gpl.html</a>.<br>
+# Mid-level API: Business logic around storage volumes<br>
+module StorageVolumeService<br>
+<br>
+ include ApplicationService<br>
+<br>
+ # Load the StorageVolume with +id+ for viewing<br>
+ #<br>
+ # === Instance variables<br>
+ # [<tt>@storage_volume</tt>] stores the Storage Volume with +id+<br>
+ # [<tt>@storage_pool</tt>] stores the Storage Volume's Storage Pool<br>
+ # === Required permissions<br>
+ # [<tt>Privilege::VIEW</tt>] on StorageVolume's HardwarePool<br>
+ def svc_show(id)<br>
+ lookup(id,Privilege::VIEW)<br>
+ end<br>
+<br>
+ # Load the StorageVolume with +id+ for editing<br>
+ #<br>
+ # === Instance variables<br>
+ # [<tt>@storage_volume</tt>] stores the Storage Volume with +id+<br>
+ # [<tt>@storage_pool</tt>] stores the Storage Volume's Storage Pool<br>
+ # === Required permissions<br>
+ # [<tt>Privilege::MODIFY</tt>] on StorageVolume's HardwarePool<br>
+ def svc_modify(id)<br>
+ lookup(id,Privilege::MODIFY)<br>
+ end<br>
+<br>
+ # Load a new StorageVolume for creating<br>
+ #<br>
+ # === Instance variables<br>
+ # [<tt>@storage_volume</tt>] loads a new StorageVolume object into memory<br>
+ # [<tt>@storage_pool</tt>] Storage pool containing <tt>@storage_volume</tt><br>
+ # [<tt>@source_volume</tt>] Storage volume containing the LVM<br>
+ # <tt>@storage_pool</tt> if storage type is LVM<br>
+ # === Required permissions<br>
+ # [<tt>Privilege::MODIFY</tt>] for the storage volume's HardwarePool<br>
+ def svc_new(storage_pool_id, source_volume_id)<br>
+ if storage_pool_id<br>
+ @storage_pool = StoragePool.find(storage_pool_id)<br>
+ unless @storage_pool.user_subdividable<br>
+ raise ActionError.new("Unsupported action for " +<br>
+ "#{@storage_pool.get_type_label} volumes.")<br>
+ end<br>
+ else<br>
+ @source_volume = StorageVolume.find(source_volume_id)<br>
+ @storage_pool = @source_volume.storage_pool<br>
+ unless @source_volume.supports_lvm_subdivision<br>
+ raise ActionError.new("LVM is not supported for this storage volume")<br>
+ end<br>
+ end<br>
+ authorized!(Privilege::MODIFY,@storage_pool.hardware_pool)<br>
+<br>
+ if source_volume_id<br>
+ @storage_pool = @source_volume.lvm_storage_pool<br>
+ unless @storage_pool<br>
+ # FIXME: what should we do about VG/LV names?<br>
+ # for now auto-create VG name as ovirt_vg_#{@<a href="http://source_volume.id" target="_blank">source_volume.id</a>}<br>
+ new_params = { :vg_name => "ovirt_vg_#{@<a href="http://source_volume.id" target="_blank">source_volume.id</a>}",<br>
+ :hardware_pool_id => @source_volume.storage_pool.hardware_pool_id}<br>
+ @storage_pool = StoragePool.factory(StoragePool::LVM, new_params)<br>
+ @storage_pool.source_volumes << @source_volume<br>
+ @storage_pool.save!<br>
+ end<br>
+ end<br>
+ @storage_volume = StorageVolume.factory(@storage_pool.get_type_label,<br>
+ { :storage_pool_id =><br>
+ @<a href="http://storage_pool.id" target="_blank">storage_pool.id</a>})<br>
+ end<br>
+<br>
+ # Create a new StorageVolume<br>
+ #<br>
+ # === Instance variables<br>
+ # [<tt>@storage_volume</tt>] the newly-created StorageVolume<br>
+ # === Required permissions<br>
+ # [<tt>Privilege::MODIFY</tt>] for the storage volume's HardwarePool<br>
+ def svc_create(storage_type, storage_volume_hash)<br>
+ @storage_volume = StorageVolume.factory(storage_type, storage_volume_hash)<br>
+ authorized!(Privilege::MODIFY,@storage_volume.storage_pool.hardware_pool)<br>
+ StorageVolume.transaction do<br>
+ @storage_volume.save!<br>
+ @task = StorageVolumeTask.new({ :user => @user,<br>
+ :task_target => @storage_volume,<br>
+ :action => StorageVolumeTask::ACTION_CREATE_VOLUME,<br>
+ :state => Task::STATE_QUEUED})<br>
+ @task.save!<br>
+ end<br>
+ return "Storage Volume was successfully created."<br>
+ end<br>
+<br>
+ # Queues StorageVolume with +id+ for deletion<br>
+ #<br>
+ # === Instance variables<br>
+ # [<tt>@storage_volume</tt>] stores the Storage Volume with +id+<br>
+ # [<tt>@storage_pool</tt>] stores the Storage Volume's Storage Pool<br>
+ # === Required permissions<br>
+ # [<tt>Privilege::MODIFY</tt>] on StorageVolume's HardwarePool<br>
+ def svc_destroy(id)<br>
+ lookup(id, Privilege::MODIFY)<br>
+ unless @storage_pool.user_subdividable<br>
+ raise ActionError.new("Unsupported action for " +<br>
+ "#{@storage_volume.get_type_label} volumes.")<br>
+ end<br>
+ unless @storage_volume.vms.empty?<br>
+ vms = @storage_volume.vms.collect {|vm| vm.description}.join(", ")<br>
+ raise ActionError.new("Cannot delete storage assigned to VMs (#{vms})")<br>
+ end<br>
+ name = @storage_volume.display_name<br>
+ StorageVolume.transaction do<br>
+ @storage_volume.state=StorageVolume::STATE_PENDING_DELETION<br>
+ @storage_volume.save!<br>
+ @task = StorageVolumeTask.new({ :user => @user,<br>
+ :task_target => @storage_volume,<br>
+ :action => StorageVolumeTask::ACTION_DELETE_VOLUME,<br>
+ :state => Task::STATE_QUEUED})<br>
+ @task.save!<br>
+ end<br>
+ return "Storage Volume #{name} deletion was successfully queued."<br>
+ end<br>
+<br>
+ private<br>
+ def lookup(id, priv)<br>
+ @storage_volume = StorageVolume.find(id)<br>
+ @storage_pool = @storage_volume.storage_pool<br>
+ authorized!(priv,@storage_pool.hardware_pool)<br>
+ end<br>
+<br>
+end<br>
<font color="#888888">--<br>
1.6.0.6<br>
<br>
_______________________________________________<br>
Ovirt-devel mailing list<br>
<a href="mailto:Ovirt-devel@redhat.com">Ovirt-devel@redhat.com</a><br>
<a href="https://www.redhat.com/mailman/listinfo/ovirt-devel" target="_blank">https://www.redhat.com/mailman/listinfo/ovirt-devel</a><br>
</font></blockquote></div><br>