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>