[Ovirt-devel] [PATCH server] converted storage volume controller to use the service layer

Scott Seago sseago at redhat.com
Wed May 13 20:13:19 UTC 2009


Signed-off-by: Scott Seago <sseago at redhat.com>
---
 src/app/controllers/storage_volume_controller.rb |  164 +++++-----------------
 src/app/models/lvm_storage_volume.rb             |    8 +
 src/app/services/storage_volume_service.rb       |  145 +++++++++++++++++++
 3 files changed, 187 insertions(+), 130 deletions(-)
 create mode 100644 src/app/services/storage_volume_service.rb

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




More information about the ovirt-devel mailing list