[Ovirt-devel] [PATCH] finished smart pools implementation. (revised)

Scott Seago sseago at redhat.com
Thu Sep 18 21:06:40 UTC 2008


Nav now works for smart pools (but Jay's going to do some tweaking). All of the smart pool tabs work properly with add/remove functions, although summary is stubbed out.
search results are not yet integrated with smart pools.

Signed-off-by: Scott Seago <sseago at redhat.com>
---
 src/app/controllers/application.rb                 |   13 +-
 src/app/controllers/hardware_controller.rb         |  122 +++--------
 src/app/controllers/host_controller.rb             |    5 +
 src/app/controllers/pool_controller.rb             |   31 +++-
 src/app/controllers/resources_controller.rb        |    4 +-
 src/app/controllers/smart_pool_controller.rb       |   22 --
 src/app/controllers/smart_pools_controller.rb      |  239 ++++++++++++++++++++
 src/app/controllers/storage_controller.rb          |    5 +
 src/app/controllers/tree_controller.rb             |   14 +-
 src/app/controllers/vm_controller.rb               |    5 +
 src/app/models/directory_pool.rb                   |    1 +
 src/app/models/pool.rb                             |   42 +++-
 src/app/models/smart_pool.rb                       |   23 ++
 src/app/views/hardware/_move_menu.rhtml            |   17 --
 src/app/views/hardware/show_hosts.rhtml            |   20 +-
 src/app/views/hardware/show_storage.rhtml          |   14 +-
 src/app/views/hardware/show_vms.rhtml              |    2 +-
 src/app/views/host/_grid.rhtml                     |   14 +-
 src/app/views/host/add_to_smart_pool.rhtml         |   28 +++
 src/app/views/host/addhost.html.erb                |    2 +-
 src/app/views/layouts/_navigation_tabs.rhtml       |   17 ++
 src/app/views/layouts/_side_toolbar.rhtml          |   45 +++--
 src/app/views/layouts/_tree.rhtml                  |    6 +-
 src/app/views/layouts/redux.rhtml                  |   26 --
 src/app/views/resources/show_vms.rhtml             |    8 +-
 src/app/views/smart_pools/_form.rhtml              |    6 +
 src/app/views/smart_pools/_pools_grid.rhtml        |   39 ++++
 src/app/views/smart_pools/add_pool_dialog.rhtml    |   52 +++++
 src/app/views/smart_pools/new.rhtml                |   26 ++
 src/app/views/smart_pools/show.rhtml               |   17 ++
 .../{hardware => smart_pools}/show_hosts.rhtml     |   64 ++---
 src/app/views/smart_pools/show_pools.rhtml         |   74 ++++++
 src/app/views/smart_pools/show_storage.rhtml       |   72 ++++++
 src/app/views/smart_pools/show_users.rhtml         |    2 +
 src/app/views/smart_pools/show_vms.rhtml           |   77 +++++++
 src/app/views/storage/_grid.rhtml                  |   19 ++-
 src/app/views/storage/add_to_smart_pool.rhtml      |   22 ++
 src/app/views/user/_show.rhtml                     |    4 +-
 src/app/views/vm/_grid.rhtml                       |   70 ++++---
 src/app/views/vm/add_to_smart_pool.rhtml           |   27 +++
 src/db/migrate/017_add_smart_pools.rb              |    2 +-
 .../jquery-treeview/jquery.treeview.async.js       |    2 +-
 src/public/javascripts/jquery.ovirt.treeview.js    |   12 +-
 src/public/javascripts/ovirt.js                    |   98 ++++++++-
 44 files changed, 1112 insertions(+), 298 deletions(-)
 delete mode 100644 src/app/controllers/smart_pool_controller.rb
 create mode 100644 src/app/controllers/smart_pools_controller.rb
 delete mode 100644 src/app/views/hardware/_move_menu.rhtml
 create mode 100644 src/app/views/host/add_to_smart_pool.rhtml
 create mode 100644 src/app/views/smart_pools/_form.rhtml
 create mode 100644 src/app/views/smart_pools/_pools_grid.rhtml
 create mode 100644 src/app/views/smart_pools/add_pool_dialog.rhtml
 create mode 100644 src/app/views/smart_pools/new.rhtml
 create mode 100644 src/app/views/smart_pools/show.rhtml
 copy src/app/views/{hardware => smart_pools}/show_hosts.rhtml (50%)
 create mode 100644 src/app/views/smart_pools/show_pools.rhtml
 create mode 100644 src/app/views/smart_pools/show_storage.rhtml
 create mode 100644 src/app/views/smart_pools/show_users.rhtml
 create mode 100644 src/app/views/smart_pools/show_vms.rhtml
 create mode 100644 src/app/views/storage/add_to_smart_pool.rhtml
 create mode 100644 src/app/views/vm/add_to_smart_pool.rhtml

diff --git a/src/app/controllers/application.rb b/src/app/controllers/application.rb
index 3126748..6dcf6f8 100644
--- a/src/app/controllers/application.rb
+++ b/src/app/controllers/application.rb
@@ -89,7 +89,7 @@ class ApplicationController < ActionController::Base
   end
 
   # don't define find_opts for array inputs
-  def json_hash(full_items, attributes, arg_list=[], find_opts={})
+  def json_hash(full_items, attributes, arg_list=[], find_opts={}, id_method=:id)
     page = params[:page].to_i
     paginate_opts = {:page => page, 
                      :order => "#{params[:sortname]} #{params[:sortorder]}", 
@@ -101,7 +101,7 @@ class ApplicationController < ActionController::Base
     json_hash[:total] = item_list.total_entries
     json_hash[:rows] = item_list.collect do |item|
       item_hash = {}
-      item_hash[:id] = item.id
+      item_hash[:id] = item.send(id_method)
       item_hash[:cell] = attributes.collect do |attr| 
         if attr.is_a? Array
           value = item
@@ -115,9 +115,12 @@ class ApplicationController < ActionController::Base
     end
     json_hash
   end
-  # don't define find_opts for array inputs
-  def json_list(full_items, attributes, arg_list=[], find_opts={})
-    render :json => json_hash(full_items, attributes, arg_list, find_opts).to_json
+
+  # json_list is a helper method used to format data for paginated flexigrid tables
+  #
+  # FIXME: what is the intent of this comment? don't define find_opts for array inputs
+  def json_list(full_items, attributes, arg_list=[], find_opts={}, id_method=:id)
+    render :json => json_hash(full_items, attributes, arg_list, find_opts, id_method).to_json
   end
 
 
diff --git a/src/app/controllers/hardware_controller.rb b/src/app/controllers/hardware_controller.rb
index a366e4c..42ff9cb 100644
--- a/src/app/controllers/hardware_controller.rb
+++ b/src/app/controllers/hardware_controller.rb
@@ -1,4 +1,4 @@
-# 
+#
 # Copyright (C) 2008 Red Hat, Inc.
 # Written by Scott Seago <sseago at redhat.com>
 #
@@ -20,10 +20,6 @@
 
 class HardwareController < PoolController
 
-  XML_OPTS  = {
-    :include => [ :storage_pools, :hosts, :quota ]
-  }
-
   EQ_ATTRIBUTES = [ :name, :parent_id ]
 
   verify :method => [:post, :put], :only => [ :create, :update ],
@@ -59,12 +55,12 @@ class HardwareController < PoolController
   end
 
   def json_view_tree
-    json_tree_internal(Permission::PRIV_VIEW, false)
+    json_tree_internal(Permission::PRIV_VIEW, :select_hardware_and_vm_pools)
   end
   def json_move_tree
-    json_tree_internal(Permission::PRIV_MODIFY, true)
+    json_tree_internal(Permission::PRIV_MODIFY, :select_hardware_pools)
   end
-  def json_tree_internal(privilege, filter_vm_pools)
+  def json_tree_internal(privilege, filter_method)
     id = params[:id]
     if id
       @pool = Pool.find(id)
@@ -77,11 +73,9 @@ class HardwareController < PoolController
     end
     if @pool
       pools = @pool.children
-      pools = Pool.select_hardware_pools(pools) if filter_vm_pools
       open_list = []
     else
       pools = Pool.list_for_user(get_login_user,Permission::PRIV_VIEW)
-      pools = Pool.select_hardware_pools(pools) if filter_vm_pools
       current_id = params[:current_id]
       if current_id
         current_pool = Pool.find(current_id)
@@ -90,26 +84,26 @@ class HardwareController < PoolController
         open_list = []
       end
     end
+    pools = Pool.send(filter_method, pools)
 
-    render :json => Pool.nav_json(pools, open_list, filter_vm_pools)
+    render :json => Pool.nav_json(pools, open_list,
+                                  (filter_method==:select_hardware_pools))
   end
 
   def show_vms
     show
   end
 
-  def show_hosts    
-    @hardware_pools = HardwarePool.find :all
+  def show_hosts
     show
   end
-  
+
   def show_graphs
     show
   end
 
   def show_storage
     show
-    @hardware_pools = HardwarePool.find :all
   end
 
   def show_tasks
@@ -142,21 +136,16 @@ class HardwareController < PoolController
       # filtering on which pool to exclude
       id = params[:exclude_pool]
       hosts = Host
-      find_opts = {:include => :hardware_pool, 
+      find_opts = {:include => :hardware_pool,
         :conditions => ["pools.id != ?", id]}
       include_pool = true
     end
-    attr_list = []
-    attr_list << :id if params[:checkboxes]
-    attr_list << :hostname
-    attr_list << [:hardware_pool, :name] if include_pool
-    attr_list += [:uuid, :hypervisor_type, :num_cpus, :cpu_speed, :arch, :memory_in_mb, :status_str, :load_average]
-    json_list(hosts, attr_list, [:all], find_opts)
+    super(:full_items => hosts,:include_pool => include_pool,:find_opts => find_opts)
   end
 
   def vm_pools_json
-    json_list(Pool, 
-              [:id, :name, :id], 
+    json_list(Pool,
+              [:id, :name, :id],
               [@pool, :children],
               {:finder => 'call_finder', :conditions => ["type = 'VmResourcePool'"]})
   end
@@ -172,24 +161,22 @@ class HardwareController < PoolController
       # filtering on which pool to exclude
       id = params[:exclude_pool]
       storage_pools = StoragePool
-      find_opts = {:include => :hardware_pool, 
+      find_opts = {:include => :hardware_pool,
         :conditions => ["pools.id != ?", id]}
       include_pool = true
     end
-    attr_list = [:id, :display_name, :ip_addr, :get_type_label]
-    attr_list.insert(2, [:hardware_pool, :name]) if include_pool
-    json_list(storage_pools, attr_list, [:all], find_opts)
+    super(:full_items => storage_pools,:include_pool => include_pool,:find_opts => find_opts)
   end
 
   def storage_volumes_json
-    json_list(@pool.all_storage_volumes, 
+    json_list(@pool.all_storage_volumes,
               [:display_name, :size_in_gb, :get_type_label])
   end
 
   def move
     pre_modify
     @resource_type = params[:resource_type]
-    render :layout => 'popup'    
+    render :layout => 'popup'
   end
 
   def new
@@ -279,87 +266,44 @@ class HardwareController < PoolController
     end
   end
 
-  #FIXME: we need permissions checks. user must have permission on src pool
-  # in addition to the current pool (which is checked). We also need to fail
-  # for hosts that aren't currently empty
   def add_hosts
-    host_ids_str = params[:resource_ids]
-    host_ids = host_ids_str.split(",").collect {|x| x.to_i}
-
-    begin
-      @pool.transaction do
-        @pool.move_hosts(host_ids, @pool.id)
-      end
-      render :json => { :object => "host", :success => true, 
-        :alert => "Hosts were successfully added to this Hardware pool." }
-    rescue
-      render :json => { :object => "host", :success => false, 
-        :alert => "Error adding Hosts to this Hardware pool." }
-    end
+    edit_items(Host, :move_hosts, @pool.id, :add)
   end
 
-  #FIXME: we need permissions checks. user must have permission on src pool
-  # in addition to the current pool (which is checked). We also need to fail
-  # for hosts that aren't currently empty
   def move_hosts
-    target_pool_id = params[:target_pool_id]
-    host_ids_str = params[:resource_ids]
-    host_ids = host_ids_str.split(",").collect {|x| x.to_i}
-    
-    begin
-      @pool.transaction do
-        @pool.move_hosts(host_ids, target_pool_id)
-      end
-      render :json => { :object => "host", :success => true, 
-        :alert => "Hosts were successfully moved." }
-    rescue
-      render :json => { :object => "host", :success => false, 
-        :alert => "Error moving hosts." }
-    end
+    edit_items(Host, :move_hosts, params[:target_pool_id], :move)
   end
 
-  #FIXME: we need permissions checks. user must have permission on src pool
-  # in addition to the current pool (which is checked). We also need to fail
-  # for storage that aren't currently empty
   def add_storage
-    storage_pool_ids_str = params[:resource_ids]
-    storage_pool_ids = storage_pool_ids_str.split(",").collect {|x| x.to_i}
-    
-    begin
-      @pool.transaction do
-        @pool.move_storage(storage_pool_ids, @pool.id)
-      end
-      render :json => { :object => "storage_pool", :success => true, 
-        :alert => "Storage Pools were successfully added to this Hardware pool." }
-    rescue
-      render :json => { :object => "storage_pool", :success => false, 
-        :alert => "Error adding storage pools to this Hardware pool." }
-    end
+    edit_items(StoragePool, :move_storage, @pool.id, :add)
+  end
+
+  def move_storage
+    edit_items(StoragePool, :move_storage, params[:target_pool_id], :move)
   end
 
   #FIXME: we need permissions checks. user must have permission on src pool
   # in addition to the current pool (which is checked). We also need to fail
   # for storage that aren't currently empty
-  def move_storage
-    target_pool_id = params[:target_pool_id]
-    storage_pool_ids_str = params[:resource_ids]
-    storage_pool_ids = storage_pool_ids_str.split(",").collect {|x| x.to_i}
+  def edit_items(item_class, item_method, target_pool_id, item_action)
+    resource_ids_str = params[:resource_ids]
+    resource_ids = resource_ids_str.split(",").collect {|x| x.to_i}
 
     begin
       @pool.transaction do
-        @pool.move_storage(storage_pool_ids, target_pool_id)
+        @pool.send(item_method, resource_ids, target_pool_id)
       end
-      render :json => { :object => "storage_pool", :success => true, 
-        :alert => "Storage Pools were successfully moved." }
+      render :json => { :success => true,
+        :alert => "#{item_action.to_s} #{item_class.table_name.humanize} successful." }
     rescue
-      render :json => { :object => "storage_pool", :success => false, 
-        :alert => "Error moving storage pools." }
+      render :json => { :success => false,
+        :alert => "#{item_action.to_s} #{item_class.table_name.humanize} failed." }
     end
   end
 
   def removestorage
     pre_modify
-    render :layout => 'popup'    
+    render :layout => 'popup'
   end
 
   def destroy
diff --git a/src/app/controllers/host_controller.rb b/src/app/controllers/host_controller.rb
index 5174c88..417d11f 100644
--- a/src/app/controllers/host_controller.rb
+++ b/src/app/controllers/host_controller.rb
@@ -84,6 +84,11 @@ class HostController < ApplicationController
     render :layout => 'popup'    
   end
 
+  def add_to_smart_pool
+    @pool = SmartPool.find(params[:smart_pool_id])
+    render :layout => 'popup'
+  end
+
   def new
   end
 
diff --git a/src/app/controllers/pool_controller.rb b/src/app/controllers/pool_controller.rb
index ce41701..02ef290 100644
--- a/src/app/controllers/pool_controller.rb
+++ b/src/app/controllers/pool_controller.rb
@@ -23,9 +23,14 @@ class PoolController < ApplicationController
   before_filter :pre_show_pool, :only => [:show_vms, :show_users,
                                           :show_hosts, :show_storage,
                                           :users_json, :show_tasks, :tasks,
-                                          :vms_json, :vm_pools_json,
+                                          :vm_pools_json,
+                                          :pools_json, :show_pools,
                                           :storage_volumes_json, :quick_summary]
 
+  XML_OPTS  = {
+    :include => [ :storage_pools, :hosts, :quota ]
+  }
+
   def show
     respond_to do |format|
       format.html {
@@ -86,6 +91,28 @@ class PoolController < ApplicationController
     json_hash(@pool.tasks, attr_list, [:all], find_opts)
   end
 
+  def hosts_json(args)
+    attr_list = []
+    attr_list << :id if params[:checkboxes]
+    attr_list << :hostname
+    attr_list << [:hardware_pool, :name] if args[:include_pool]
+    attr_list += [:uuid, :hypervisor_type, :num_cpus, :cpu_speed, :arch, :memory_in_mb, :status_str, :load_average]
+    json_list(args[:full_items], attr_list, [:all], args[:find_opts])
+  end
+
+  def storage_pools_json(args)
+    attr_list = [:id, :display_name, :ip_addr, :get_type_label]
+    attr_list.insert(2, [:hardware_pool, :name]) if args[:include_pool]
+    json_list(args[:full_items], attr_list, [:all], args[:find_opts])
+  end
+
+  def vms_json(args)
+    attr_list = [:id, :description, :uuid,
+                 :num_vcpus_allocated, :memory_allocated_in_mb,
+                 :vnic_mac_addr, :state, :id]
+    json_list(args[:full_items], attr_list, [:all], args[:find_opts])
+  end
+
   def new
     render :layout => 'popup'
   end
@@ -120,7 +147,7 @@ class PoolController < ApplicationController
     @current_pool_id=@pool.id
     set_perms(@perm_obj)
     unless @can_view
-      flash[:notice] = 'You do not have permission to view this pool pool: redirecting to top level'
+      flash[:notice] = 'You do not have permission to view this pool: redirecting to top level'
       respond_to do |format|
         format.html { redirect_to :controller => "dashboard" }
         format.xml { head :forbidden }
diff --git a/src/app/controllers/resources_controller.rb b/src/app/controllers/resources_controller.rb
index a0a65a6..2c54ccc 100644
--- a/src/app/controllers/resources_controller.rb
+++ b/src/app/controllers/resources_controller.rb
@@ -68,8 +68,8 @@ class ResourcesController < PoolController
   end
 
   def vms_json
-    json_list(@pool.vms,
-              [:id, :description, :uuid, :num_vcpus_allocated, :memory_allocated_in_mb, :vnic_mac_addr, :state, :id])
+    pre_show
+    super(:full_items => @pool.vms, :find_opts => {}, :include_pool => :true)
   end
 
   def create
diff --git a/src/app/controllers/smart_pool_controller.rb b/src/app/controllers/smart_pool_controller.rb
deleted file mode 100644
index eb087a6..0000000
--- a/src/app/controllers/smart_pool_controller.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-#
-# Copyright (C) 2008 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.
-#
-
-class SmartPoolController < ApplicationController
-end
diff --git a/src/app/controllers/smart_pools_controller.rb b/src/app/controllers/smart_pools_controller.rb
new file mode 100644
index 0000000..99ae8b8
--- /dev/null
+++ b/src/app/controllers/smart_pools_controller.rb
@@ -0,0 +1,239 @@
+#
+# Copyright (C) 2008 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.
+#
+
+class SmartPoolsController < PoolController
+
+  before_filter :pre_modify, :only => [:add_hosts, :remove_hosts,
+                                       :add_storage, :remove_storage,
+                                       :add_vms, :remove_vms,
+                                       :add_pools, :remove_pools]
+  def show_vms
+    show
+  end
+
+  def show_hosts
+    show
+  end
+
+  def show_pools
+    show
+  end
+
+  def show_storage
+    show
+  end
+
+  def create
+    begin
+      @pool.create_with_parent(@parent)
+      render :json => { :object => "smart_pool", :success => true,
+                        :alert => "Smart Pool was successfully created." }
+    rescue
+      render :json => { :object => "smart_pool", :success => false,
+                        :errors => @pool.errors.localize_error_messages.to_a}
+    end
+  end
+
+  def update
+    begin
+      @pool.update_attributes!(params[:smart_pool])
+      render :json => { :object => "smart_pool", :success => true,
+                        :alert => "Smart Pool was successfully modified." }
+    rescue
+      render :json => { :object => "smart_pool", :success => false,
+                        :errors => @pool.errors.localize_error_messages.to_a}
+    end
+  end
+
+  def add_pool_dialog
+    pre_modify
+    @selected_pools = @pool.tagged_pools.collect {|pool| pool.id}
+    render :layout => 'popup'
+  end
+
+  def hosts_json
+    super(items_json_internal(Host, :tagged_hosts))
+  end
+
+  def storage_pools_json
+    super(items_json_internal(StoragePool, :tagged_storage_pools))
+  end
+
+  def vms_json
+    super(items_json_internal(Vm, :tagged_vms))
+  end
+
+  def pools_json
+    args = items_json_internal(Pool, :tagged_pools)
+    attr_list = [:id, :name, :get_type_label]
+    json_list(args[:full_items], attr_list, [:all], args[:find_opts], :class_and_id)
+
+  end
+
+  def items_json_internal(item_class, item_assoc)
+    if params[:id]
+      pre_show
+      full_items = @pool.send(item_assoc)
+      find_opts = {}
+    else
+      # FIXME: no permissions or usage checks here yet
+      # filtering on which pool to exclude
+      id = params[:exclude_pool]
+      full_items = item_class
+      pool_items = SmartPool.find(id,
+                   :include => item_assoc).send(item_assoc).collect {|x| x.id}
+      if pool_items.empty?
+        conditions = []
+      else
+        conditions = ["#{item_class.table_name}.id not in (?)", pool_items]
+      end
+      find_opts = {:conditions => conditions}
+    end
+    { :full_items => full_items, :find_opts => find_opts, :include_pool => :true}
+  end
+
+  def add_hosts
+    edit_items(Host, :add_items, :add)
+  end
+
+  def remove_hosts
+    edit_items(Host, :remove_items, :remove)
+  end
+
+  def add_storage
+    edit_items(StoragePool, :add_items, :add)
+  end
+
+  def remove_storage
+    edit_items(StoragePool, :remove_items, :remove)
+  end
+
+  def add_vms
+    edit_items(Vm, :add_items, :add)
+  end
+
+  def remove_vms
+    edit_items(Vm, :remove_items, :remove)
+  end
+
+  def add_pools
+    edit_items(Pool, :add_items, :add)
+  end
+
+  def remove_pools
+    edit_items(Pool, :remove_items, :remove)
+  end
+
+  def edit_items(item_class, item_method, item_action)
+    resource_ids_str = params[:resource_ids]
+    resource_ids = resource_ids_str.split(",").collect {|x| x.to_i}
+    begin
+      @pool.send(item_method,item_class, resource_ids)
+      render :json => { :success => true,
+        :alert => "#{item_action.to_s} #{item_class.table_name.humanize} successful." }
+    rescue
+      render :json => { :success => false,
+        :alert => "#{item_action.to_s} #{item_class.table_name.humanize} failed." }
+    end
+  end
+
+  def destroy
+    if @pool.destroy
+      alert="Smart Pool was successfully deleted."
+      success=true
+    else
+      alert="Failed to delete Smart pool."
+      success=false
+    end
+    render :json => { :object => "smart_pool", :success => success, :alert => alert }
+  end
+
+  # handled
+  #  show_hosts
+  #  show_graphs
+  #  show_storage
+  #  show
+  #  show_vms
+  #  show_tasks
+  #  new   xxx
+  #  create xxx
+  #  hosts_json
+  #  storage_pools_json
+  #  add_hosts
+  #  move_hosts
+  #  add_storage
+  #  move_storage
+  #  removestorage
+
+  #HW only
+  #  json_view_tree
+  #  json_move_tree
+  #  vm_pools_json
+  #  move
+  #VM only
+  #  vms_json
+  #  delete
+  #  vm_actions
+  #both
+  #  move
+  #  update
+  #  destroy
+
+  #inherited
+  #  used
+  #    new
+  #    edit
+  #    show_users
+  #    users_json
+  #  unneeded
+  #    tasks
+  #    show_tasks
+  #    quick_summary
+
+  protected
+  #filter methods
+  def pre_new
+    @pool = SmartPool.new
+    @parent = DirectoryPool.get_or_create_user_root(get_login_user)
+    @perm_obj = @parent
+    @current_pool_id=@parent.id
+  end
+  def pre_create
+    @pool = SmartPool.new(params[:smart_pool])
+    @parent = DirectoryPool.get_or_create_user_root(get_login_user)
+    @perm_obj = @parent
+    @current_pool_id=@parent.id
+  end
+  def pre_edit
+    @pool = SmartPool.find(params[:id])
+    @parent = @pool.parent
+    @perm_obj = @pool
+    @current_pool_id=@pool.id
+  end
+  def pre_show
+    @pool = SmartPool.find(params[:id])
+    super
+  end
+  def pre_modify
+    pre_edit
+    authorize_admin
+  end
+
+end
diff --git a/src/app/controllers/storage_controller.rb b/src/app/controllers/storage_controller.rb
index 7e97764..7eec618 100644
--- a/src/app/controllers/storage_controller.rb
+++ b/src/app/controllers/storage_controller.rb
@@ -199,6 +199,11 @@ class StorageController < ApplicationController
     render :layout => false
   end
 
+  def add_to_smart_pool
+    @pool = SmartPool.find(params[:smart_pool_id])
+    render :layout => 'popup'
+  end
+
   #FIXME: we need permissions checks. user must have permission on src pool
   # in addition to the current pool (which is checked). We also need to fail
   # for storage that aren't currently empty
diff --git a/src/app/controllers/tree_controller.rb b/src/app/controllers/tree_controller.rb
index 5ad8426..1aed544 100644
--- a/src/app/controllers/tree_controller.rb
+++ b/src/app/controllers/tree_controller.rb
@@ -1,10 +1,18 @@
 class TreeController < ApplicationController
-  
+
+  def get_pools
+    # TODO: split these into separate hash elements for HW and smart pools
+    pools = HardwarePool.get_default_pool.full_set_nested(:method => :json_hash_element,
+                       :privilege => Permission::PRIV_VIEW, :user => get_login_user)
+    pools += DirectoryPool.get_smart_root.full_set_nested(:method => :json_hash_element,
+                       :privilege => Permission::PRIV_VIEW, :user => get_login_user,
+                       :smart_pool_set => true)
+  end
   def fetch_nav
-    @pools = HardwarePool.get_default_pool.full_set_nested(:method => :json_hash_element)
+    @pools = get_pools
   end
   
   def fetch_json
-    render :json => HardwarePool.get_default_pool.full_set_nested(:method => :json_hash_element).to_json
+    render :json => get_pools.to_json
   end
 end
diff --git a/src/app/controllers/vm_controller.rb b/src/app/controllers/vm_controller.rb
index d3f16b6..6d06b48 100644
--- a/src/app/controllers/vm_controller.rb
+++ b/src/app/controllers/vm_controller.rb
@@ -35,6 +35,11 @@ class VmController < ApplicationController
     render :layout => 'selection'    
   end
 
+  def add_to_smart_pool
+    @pool = SmartPool.find(params[:smart_pool_id])
+    render :layout => 'popup'
+  end
+
   def new
     render :layout => 'popup'    
   end
diff --git a/src/app/models/directory_pool.rb b/src/app/models/directory_pool.rb
index f62d980..82486af 100644
--- a/src/app/models/directory_pool.rb
+++ b/src/app/models/directory_pool.rb
@@ -55,6 +55,7 @@ class DirectoryPool < Pool
         permission.save!
       end
     end
+    user_root
   end
 
 end
diff --git a/src/app/models/pool.rb b/src/app/models/pool.rb
index 9d71fa5..eb71be8 100644
--- a/src/app/models/pool.rb
+++ b/src/app/models/pool.rb
@@ -111,6 +111,9 @@ class Pool < ActiveRecord::Base
   def self.select_vm_pools(pools)
     pools.select {|pool| pool[:type] == "VmResourcePool"}
   end
+  def self.select_hardware_and_vm_pools(pools)
+    pools.select {|pool| ["HardwarePool", "VmResourcePool"].include?(pool[:type])}
+  end
 
   def sub_hardware_pools
     children({:conditions => "type='HardwarePool'"})
@@ -225,22 +228,44 @@ class Pool < ActiveRecord::Base
   # or :current_id to specify which pool gets ":selected => true" set
   def full_set_nested(opts={})
     method = opts.delete(:method) {:hash_element}
+    privilege = opts.delete(:privilege)
+    user = opts.delete(:user)
+    smart_pool_set = opts.delete(:smart_pool_set)
+    if privilege and user
+      opts[:include] = "permissions"
+      opts[:conditions] = "permissions.uid='#{user}' and
+                       permissions.user_role in
+                       ('#{Permission.roles_for_privilege(privilege).join("', '")}')"
+    end
     current_id = opts.delete(:current_id)
     opts.delete(:order)
     subtree_list = full_set(opts)
-    return_tree = send(method)
-    ref_hash = { id => return_tree}
+    subtree_list -= [self] if smart_pool_set
+    return_tree_list = []
+    ref_hash = {}
     subtree_list.each do |pool|
-      unless pool.id==return_tree[:id]
-        new_element = pool.send(method)
-        ref_hash[pool.id] = new_element
-        parent = ref_hash[pool.parent_id]
+      new_element = pool.send(method)
+      ref_hash[pool.id] = new_element
+      parent = ref_hash[pool.parent_id]
+      if parent
         parent[:children] ||= []
         parent[:children] << new_element
+      else
+        # for smart pools include the parent DirectoryPool
+        if smart_pool_set and pool[:type]=="SmartPool"
+          pool_parent = pool.parent
+          parent_element = pool_parent.send(method)
+          ref_hash[pool_parent.id] = parent_element
+          return_tree_list << parent_element
+          parent_element[:children] ||= []
+          parent_element[:children] << new_element
+        else
+          return_tree_list << new_element
+        end
       end
     end
     ref_hash[current_id][:selected] = true if current_id
-    return_tree
+    return_tree_list
   end
 
   def self.call_finder(*args)
@@ -273,6 +298,9 @@ class Pool < ActiveRecord::Base
     end
   end
 
+  def class_and_id
+    self.class.name + "_" + self.id.to_s
+  end
   protected
   def traverse_parents
     if id
diff --git a/src/app/models/smart_pool.rb b/src/app/models/smart_pool.rb
index e672c5b..9104ee5 100644
--- a/src/app/models/smart_pool.rb
+++ b/src/app/models/smart_pool.rb
@@ -30,6 +30,10 @@ class SmartPool < Pool
                    :conditions => "smart_pool_tags.tagged_type = 'Vm'"
 
 
+  def get_type_label
+    "Smart Pool"
+  end
+
   def create_for_user(user)
     create_with_parent(DirectoryPool.get_or_create_user_root(user))
   end
@@ -44,4 +48,23 @@ class SmartPool < Pool
                                   :tagged_id=>item.id}).destroy
   end
 
+  def add_items(item_class, item_ids)
+    items = item_class.find(:all, :conditions => "id in (#{item_ids.join(', ')})")
+    transaction do
+      items.each { |item| add_item(item)}
+    end
+  end
+
+  def remove_items(item_class, item_ids)
+      tags = smart_pool_tags.find(:all,
+                                  :conditions => "tagged_id in
+                                                  (#{item_ids.join(', ')})
+                                                  and tagged_type='#{item_class.name}'")
+      transaction do
+        tags.each do |tag|
+          tag.destroy
+        end
+      end
+  end
+
 end
diff --git a/src/app/views/hardware/_move_menu.rhtml b/src/app/views/hardware/_move_menu.rhtml
deleted file mode 100644
index cc7ed73..0000000
--- a/src/app/views/hardware/_move_menu.rhtml
+++ /dev/null
@@ -1,17 +0,0 @@
-<%= image_tag "icon_move.png", :style => "vertical-align:middle;" %>  Move    <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %>
-<ul>
-   <% @hardware_pools.each { |hw_pool| %>
-      <% if @pool.parent_id != hw_pool.id  and @pool.id != hw_pool.id %>
-         <li onclick="window.location='<%= url_for :controller => :hardware, :action => 'foobar' %>'">  <!-- FIXME point me at the right place -->
-      <% else %>
-         <li style="color: #CCCCCC; cursor: default;">
-      <% end %>
-            <%= image_tag "icon_hdwarepool.png" %>
-              <%= hw_pool.name %></a>
-         </li>
-   <% } %>
-
-   <li style="border-top: 1px solid black; border-bottom: 1px solid black;">
-       Move to New Resource Group...
-   </li>
-</ul>
diff --git a/src/app/views/hardware/show_hosts.rhtml b/src/app/views/hardware/show_hosts.rhtml
index 31c575d..d33c920 100644
--- a/src/app/views/hardware/show_hosts.rhtml
+++ b/src/app/views/hardware/show_hosts.rhtml
@@ -14,17 +14,17 @@
 <script type="text/javascript">
   function get_selected_hosts()
   {
-    return get_selected_checkboxes("hosts_grid_form")
+    return get_selected_checkboxes("hosts_grid_form");
   }
   function validate_for_move()
   {
     if (validate_selected(get_selected_hosts(), 'host')) {
-      $('#move_link_hidden').click()
+      $('#move_link_hidden').click();
     }
   }
   function remove_hosts()
   {
-    hosts = get_selected_hosts()
+    var hosts = get_selected_hosts();
     if (validate_selected(hosts, "host")) {
       $.post('<%= url_for :controller => "hardware", :action => "move_hosts", :id => @pool %>',
              { resource_ids: hosts.toString(), target_pool_id: <%= HardwarePool.get_default_pool.id %> },
@@ -34,22 +34,22 @@
 		  $.jGrowl(data.alert);
                 }
 		if (hosts.indexOf($('#hosts_selection_id').html()) != -1){
-		  empty_summary('hosts_selection', 'Host')
-		}   
+		  empty_summary('hosts_selection', 'Host');
+		}
 
                }, 'json');
     }
   }
   function hosts_select(selected_rows)
   {
-    var selected_ids = new Array() 
-    for(i=0; i<selected_rows.length; i++) { 
+    var selected_ids = new Array();
+    for(i=0; i<selected_rows.length; i++) {
       load_widget_select(selected_rows[i]);
       selected_ids[i] = selected_rows[i].id;
     }
     if (selected_ids.length == 1)
     {
-      $('#hosts_selection').load('<%= url_for :controller => "host", :action => "show", :id => nil %>/' + parseInt(selected_ids[0].substring(3)))
+      $('#hosts_selection').load('<%= url_for :controller => "host", :action => "show", :id => nil %>/' + parseInt(selected_ids[0].substring(3)));
     }
   }
 </script>
@@ -63,7 +63,7 @@
                                                         :exclude_host => nil,
                                                         :show_pool => false,
                                                         :checkboxes => true,
-                                                        :on_select => "hosts_select", 
+                                                        :on_select => "hosts_select",
                                                         :on_deselect => "load_widget_deselect",
                                                         :on_hover => "load_widget_hover",
                                                         :on_unhover => "load_widget_unhover",
@@ -79,7 +79,7 @@
    <div class="data_section">
        <div class="no-grid-items">
           <%= image_tag 'no-grid-items.png', :style => 'float: left;' %>
-          
+
           <div class="no-grid-items-text">
             No hosts found in this pool. <br/><br/>
             <%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %>  
diff --git a/src/app/views/hardware/show_storage.rhtml b/src/app/views/hardware/show_storage.rhtml
index 564b9ed..6466f9b 100644
--- a/src/app/views/hardware/show_storage.rhtml
+++ b/src/app/views/hardware/show_storage.rhtml
@@ -15,7 +15,7 @@
 <script type="text/javascript">
   function remove_storage()
   {
-    storage = get_selected_storage()
+    var storage = get_selected_storage();
     if (validate_selected(storage, "storage pool")) {
       $.post('<%= url_for :controller => "hardware", :action => "move_storage", :id => @pool %>',
              { resource_ids: storage.toString(), target_pool_id: <%= HardwarePool.get_default_pool.id %> },
@@ -25,14 +25,14 @@
 		  $.jGrowl(data.alert);
                 }
 		if (storage.indexOf($('#storage_selection_id').html()) != -1){
-		  empty_summary('storage_selection', 'Storage Pool')
+		  empty_summary('storage_selection', 'Storage Pool');
 		}   
                }, 'json');
     }
   }
   function delete_storage()
   {
-    storage = get_selected_storage()
+    var storage = get_selected_storage();
     if (validate_selected(storage, "storage pool")) {
       $.post('<%= url_for :controller => "storage", :action => "delete_pools", :id => @pool %>',
              { storage_pool_ids: storage.toString() },
@@ -42,15 +42,15 @@
 		  $.jGrowl(data.alert);
                 }
 		if (storage.indexOf($('#storage_selection_id').html()) != -1){
-		  empty_summary('storage_selection', 'Storage Pool')
+		  empty_summary('storage_selection', 'Storage Pool');
 		}   
                }, 'json');
     }
   }
   function storage_select(selected_rows)
   {
-    var selected_ids = new Array() ;
-    for(i=0; i<selected_rows.length; i++) { 
+    var selected_ids = new Array();
+    for(i=0; i<selected_rows.length; i++) {
       selected_ids[i] = selected_rows[i].id;
     }
     if (selected_ids.length == 1)
@@ -80,7 +80,7 @@
    <div class="data_section">
        <div class="no-grid-items">
           <%= image_tag 'no-grid-items.png', :style => 'float: left;' %>
-          
+
           <div class="no-grid-items-text">
             No storage Volumes found in this pool. <br/><br/>
             <%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %>  
diff --git a/src/app/views/hardware/show_vms.rhtml b/src/app/views/hardware/show_vms.rhtml
index 5ff5cc9..ee14758 100644
--- a/src/app/views/hardware/show_vms.rhtml
+++ b/src/app/views/hardware/show_vms.rhtml
@@ -11,7 +11,7 @@
   }
   function delete_vm_pools()
   {
-    vm_pools = get_selected_vm_pools()
+    var vm_pools = get_selected_vm_pools();
     if (validate_selected(vm_pools, "vm_pool")) {
       $.post('<%= url_for :controller => "resources", :action => "delete", :id => @pool %>',
              { vm_pool_ids: vm_pools.toString() },
diff --git a/src/app/views/host/_grid.rhtml b/src/app/views/host/_grid.rhtml
index 553adf9..21b563e 100644
--- a/src/app/views/host/_grid.rhtml
+++ b/src/app/views/host/_grid.rhtml
@@ -1,6 +1,14 @@
 <%= render :partial => 'graph/load_graph.rhtml' %>
+<% pool_controller = 'hardware' unless (defined? pool_controller) and !(pool_controller.nil?) %>
 
 <% hosts_per_page.nil? ? hosts_per_page = 40: hosts_per_page = hosts_per_page %>
+<% if (hwpool.nil? or
+       ((hwpool.is_a? HardwarePool) and (hwpool.hosts.size > hosts_per_page)) or
+       ((hwpool.is_a? SmartPool) and (hwpool.tagged_hosts.size > hosts_per_page)))
+     usepager = 'true'
+   else
+     usepager = 'false'
+   end %>
 <div id="<%= table_id %>_div">
 <%= "<form id=\"#{table_id}_form\">" if checkboxes %>
 <table id="<%= table_id %>" style="display:none"></table>
@@ -10,7 +18,7 @@
     $("#<%= table_id %>").flexigrid
     (
     {
-    url: '<%=  url_for :controller => "hardware",
+    url: '<%=  url_for :controller => pool_controller,
                        :action => "hosts_json",
                        :escape => false,
                        :id => (hwpool.nil? ? nil : hwpool.id),
@@ -38,8 +46,8 @@
 	],
     sortname: "hostname",
     sortorder: "asc",
-    usepager: <%= (hwpool.nil? or hwpool.hosts.size > hosts_per_page) ? 'true' : 'false' %>,
-    useRp: <%= (hwpool.nil? or hwpool.hosts.size > hosts_per_page) ? 'true' : 'false' %>,
+    usepager: <%= usepager %>,
+    useRp: <%= usepager %>,
     rp: <%= hosts_per_page %>,
     showTableToggleBtn: true,
     onSelect: <%= on_select %>,
diff --git a/src/app/views/host/add_to_smart_pool.rhtml b/src/app/views/host/add_to_smart_pool.rhtml
new file mode 100644
index 0000000..a89f8de
--- /dev/null
+++ b/src/app/views/host/add_to_smart_pool.rhtml
@@ -0,0 +1,28 @@
+<%- content_for :title do -%>
+  <%= _("Add Host to Smart Pool") %>
+<%- end -%>
+<%- content_for :description do -%>
+  Select hosts from the list below to add to the <%= @pool.name %> smart pool.</a>
+<%- end -%>
+<div id="dialog-content-area">
+<div class="dialog_body_small">
+<div class="panel_header"></div>
+  <%= render :partial => "/host/grid", :locals => { :table_id => "add_smart_hosts_grid",
+             :hwpool => nil,
+             :pool_controller => "smart_pools",
+             :exclude_pool => @pool.id,
+             :exclude_host => nil,
+             :checkboxes => true,
+             :on_select => false,
+             :on_deselect => false,
+             :on_hover => false,
+             :on_unhover => false,
+             :is_popup => true,
+             :hosts_per_page => 10} %>
+</div>
+
+<%= popup_footer("add_hosts_to_smart_pool('#{url_for :controller => "smart_pools",
+                                                     :action => "add_hosts",
+                                                     :id => @pool}')",
+                 "Add Hosts") %>
+</div>
diff --git a/src/app/views/host/addhost.html.erb b/src/app/views/host/addhost.html.erb
index 7edd4c5..967643e 100644
--- a/src/app/views/host/addhost.html.erb
+++ b/src/app/views/host/addhost.html.erb
@@ -24,4 +24,4 @@
                                       :action => "add_hosts", 
                                       :id => @hardware_pool}')", 
                  "Add Hosts") %>
-</div>
\ No newline at end of file
+</div>
diff --git a/src/app/views/layouts/_navigation_tabs.rhtml b/src/app/views/layouts/_navigation_tabs.rhtml
index 4b0f18d..af3fa61 100644
--- a/src/app/views/layouts/_navigation_tabs.rhtml
+++ b/src/app/views/layouts/_navigation_tabs.rhtml
@@ -30,6 +30,23 @@
     <li id="nav_access"> <%= link_to "User Access", {:action => 'show_users', :id => @pool.id, :nolayout => :true}, :title => "content area" %></li>
     <li id="nav_tasks">  <%= link_to "Tasks", {:action => 'show_tasks', :id => @pool.id, :nolayout => :true}, :title => "content area" %></li>
   </ul>
+<% elsif controller.controller_name == "smart_pools"  %>
+  <script>
+    $(document).ready(function(){
+      $tabs = $("#smart_pools_nav_tabs").tabs({
+          pool_type: "smart_pools",
+          selected: <%if params[:tab]%><%=params[:tab]%><%else%>1<%end%>
+      });
+    });
+  </script>
+  <ul id="smart_pools_nav_tabs" class="ui-tabs-nav">
+    <li id="nav_summary" class="ui-tabs-selected"><%= link_to "Summary", {:action => 'show', :id => @pool.id, :nolayout => :true}, :title => "content area" %></li>
+    <li id="nav_hosts">  <%= link_to "Hosts", {:action => 'show_hosts', :id => @pool.id, :nolayout => :true}, :title => "content area" %></li>
+    <li id="nav_storage"><%= link_to "Storage", {:action => 'show_storage', :id => @pool.id, :nolayout => :true}, :title => "content area" %></li>
+    <li id="nav_pools"> <%= link_to "Pools", {:action => 'show_pools', :id => @pool.id, :nolayout => :true}, :title => "content area" %></li>
+    <li id="nav_vms"> <%= link_to "Virtual Machines", {:action => 'show_vms', :id => @pool.id, :nolayout => :true}, :title => "content area" %></li>
+    <li id="nav_access"> <%= link_to "User Access", {:action => 'show_users', :id => @pool.id, :nolayout => :true}, :title => "content area" %></li>
+  </ul>
 <% elsif controller.controller_name == "search"  %>
   <ul id="resources_nav_tabs" class="ui-tabs-nav">
     <li id="nav_search" class="ui-tabs-selected"><a href="#">Search Results</a></li>
diff --git a/src/app/views/layouts/_side_toolbar.rhtml b/src/app/views/layouts/_side_toolbar.rhtml
index 763f4a2..e1958f1 100644
--- a/src/app/views/layouts/_side_toolbar.rhtml
+++ b/src/app/views/layouts/_side_toolbar.rhtml
@@ -1,24 +1,41 @@
 <% pool = @current_pool_id ? Pool.find(@current_pool_id) : nil %>
+<% if pool and pool[:type]=="HardwarePool"
+     delete_url = url_for(:controller => "hardware", :action => "destroy")
+   elsif pool and pool[:type]=="VmResourcePool"
+     delete_url = url_for(:controller => "resources", :action => "destroy")
+   elsif pool and pool[:type]=="SmartPool"
+     delete_url = url_for(:controller => "smart_pools", :action => "destroy")
+   else
+     delete_url = ""
+   end %>
+
 <%if pool -%>
-<%if pool[:type]=="HardwarePool" -%>
-<div class="toolbar" style="float:left;">
-   <a href="<%= url_for :controller => :hardware, :action => 'new', :parent_id => pool %>" rel="facebox[.bolder]">
-     <%=image_tag "icon_add_hardwarepool.png", :title=>"Add Hardware Pool"  %>
-   </a>
-</div>
+  <%if pool[:type]=="HardwarePool" -%>
+    <div class="toolbar" style="float:left;">
+      <a href="<%= url_for :controller => :hardware, :action => 'new', :parent_id => pool %>" rel="facebox[.bolder]">
+       <%=image_tag "icon_add_hardwarepool.png", :title=>"Add Hardware Pool"  %>
+      </a>
+    </div>
+    <div class="toolbar" style="float:left;">
+      <a href="<%= url_for :controller => 'resources', :action => 'new', :parent_id => pool %>" rel="facebox[.bolder]">
+        <%= image_tag "icon_add_vmpool.png", :title=>"Add Virtual Machine Pool" %>
+      </a>
+    </div>
+  <% end -%>
+<% end -%>
 <div class="toolbar" style="float:left;">
-   <a href="<%= url_for :controller => 'resources', :action => 'new', :parent_id => pool %>" rel="facebox[.bolder]">
-     <%= image_tag "icon_add_vmpool.png", :title=>"Add Virtual Machine Pool" %>
+   <a href="<%= url_for :controller => :smart_pools, :action => 'new' %>" rel="facebox[.bolder]">
+     <%=image_tag "icon_add_hardwarepool.png", :title=>"Add Smart Pool"  %>
    </a>
 </div>
-<% end -%>
-<div class="toolbar" style="float:left;">
+<%if pool -%>
+  <div class="toolbar" style="float:left;">
     <a href="#conf_nav_delete_pool" rel="facebox[.bolder]">
       <%= image_tag "icon_delete.gif", :title=>"Delete Selected Pool" %>
     </a> 
-</div>
-<div class="toolbar" style="display:none;">
-  <%= confirmation_dialog("conf_nav_delete_pool", "Are you sure?", "delete_#{pool[:type]=='HardwarePool' ? 'hw' : 'vm'}_pool(#{pool.id})") %>
-</div>
+  </div>
+  <div class="toolbar" style="display:none;">
+    <%= confirmation_dialog("conf_nav_delete_pool", "Are you sure?", "delete_pool('#{delete_url}', #{pool.id})") %>
+  </div>
 <% end -%>
 <div class="toolbar"></div>
diff --git a/src/app/views/layouts/_tree.rhtml b/src/app/views/layouts/_tree.rhtml
index eb15676..0e6e138 100644
--- a/src/app/views/layouts/_tree.rhtml
+++ b/src/app/views/layouts/_tree.rhtml
@@ -12,12 +12,14 @@
             //animated: "normal",
             url: "<%=  url_for :controller =>'/tree', :action => 'fetch_json' %>",
             hardware_url: "<%=  url_for :controller =>'/hardware', :action => 'show' %>",
-            resource_url: "<%=  url_for :controller =>'/resources', :action => 'show' %>"
+            resource_url: "<%=  url_for :controller =>'/resources', :action => 'show' %>",
+            smart_url: "<%=  url_for :controller =>'/smart_pools', :action => 'show' %>"
 	});
         var tree_reload = {
             url: "<%=  url_for :controller =>'/tree', :action => 'fetch_json' %>",
             hardware_url: "<%=  url_for :controller =>'/hardware', :action => 'show' %>",
-            resource_url: "<%=  url_for :controller =>'/resources', :action => 'show' %>"
+            resource_url: "<%=  url_for :controller =>'/resources', :action => 'show' %>",
+            smart_url: "<%=  url_for :controller =>'/smart_pools', :action => 'show' %>"
         }
         $('#test-tree').everyTime(15000,function(){
           load(tree_reload, {}, this, this);
diff --git a/src/app/views/layouts/redux.rhtml b/src/app/views/layouts/redux.rhtml
index d6cfe24..01540d4 100644
--- a/src/app/views/layouts/redux.rhtml
+++ b/src/app/views/layouts/redux.rhtml
@@ -90,32 +90,6 @@
                     });
                     return false;})},function(){});
 	});
-
-  function delete_vm_pool(id, parent)
-  {
-    $(document).trigger('close.facebox');
-    $.post('<%= url_for :controller => "resources", :action => "destroy" %>',
-           {id: id},
-            function(data,status){
-              // need to redirect to the parent using the new ajax reload stuff
-              $("#vmpools_grid").flexReload();
-              if (data.alert) {
-                $.jGrowl(data.alert);
-              }
-             }, 'json');
-  }
-  function delete_hw_pool(id, parent)
-  {
-    $(document).trigger('close.facebox');
-    $.post('<%= url_for :controller => "hardware", :action => "destroy" %>',
-           {id: id},
-            function(data,status){
-              // need to redirect to the parent using the new ajax reload stuff
-              if (data.alert) {
-                $.jGrowl(data.alert);
-              }
-             }, 'json');
-  }
       </script>
    <%= yield :scripts -%>
  </head>
diff --git a/src/app/views/resources/show_vms.rhtml b/src/app/views/resources/show_vms.rhtml
index 857f56b..beca048 100644
--- a/src/app/views/resources/show_vms.rhtml
+++ b/src/app/views/resources/show_vms.rhtml
@@ -26,7 +26,7 @@
   }
   function delete_vms()
   {
-    vms = get_selected_vms()
+    var vms = get_selected_vms();
     if (validate_selected(vms, "vm")) {
       $.post('<%= url_for :controller => "vm", :action => "delete", :id => @pool %>',
              { vm_ids: vms.toString() },
@@ -43,7 +43,7 @@
   }
   function vm_actions(action)
   {
-    vms = get_selected_vms()
+    var vms = get_selected_vms();
     if (validate_selected(vms, "vm")) {
       jQuery.facebox('<div id="vm_action_results">');
       $('#vm_action_results').load('<%= url_for :controller => "resources", 
@@ -70,10 +70,12 @@
   <div class="data_section">
        <%= render :partial => "/vm/grid", :locals => { :table_id => "vms_grid",
                                                        :pool => @pool,
+                                                       :exclude_pool => nil,
                                                        :on_select => "vms_select",
                                                        :on_deselect => "load_widget_deselect",
                                                        :on_hover => "load_widget_hover",
-                                                       :on_unhover => "load_widget_unhover" } %>
+                                                       :on_unhover => "load_widget_unhover",
+                                                       :is_popup => false } %>
   </div>
   <div class="selection_detail" id="vms_selection">
      <div class="selection_left">
diff --git a/src/app/views/smart_pools/_form.rhtml b/src/app/views/smart_pools/_form.rhtml
new file mode 100644
index 0000000..2f2156a
--- /dev/null
+++ b/src/app/views/smart_pools/_form.rhtml
@@ -0,0 +1,6 @@
+<%= error_messages_for 'vm_resource_pool' %>
+
+<!--[form:vm_resource_pool]-->
+<%= text_field_with_label "Name", 'smart_pool', 'name'  %>
+<!--[eoform:vm_resource_pool]-->
+
diff --git a/src/app/views/smart_pools/_pools_grid.rhtml b/src/app/views/smart_pools/_pools_grid.rhtml
new file mode 100644
index 0000000..a5f1a99
--- /dev/null
+++ b/src/app/views/smart_pools/_pools_grid.rhtml
@@ -0,0 +1,39 @@
+<% resources_per_page = 40 %>
+<div id="<%= table_id %>_div">
+<form id="<%= table_id %>_form">
+<table id="<%= table_id %>" style="display:none"></table>
+</form>
+</div>
+<script type="text/javascript">
+    $("#<%= table_id %>").flexigrid
+    (
+    {
+    url: '<%=  url_for :controller => "smart_pools", :action => "pools_json", :id => pool.id %>',
+    dataType: 'json',
+    colModel : [
+        {display: '', name : 'id', width : 20, sortable : false, align: 'left', process: <%= table_id %>checkbox},
+        {display: 'Name', name : 'name', width : 160, sortable : true, align: 'left'},
+        {display: 'Type', width : 160, sortable : true, align: 'left'}
+        ],
+    sortname: "name",
+    sortorder: "asc",
+    usepager: <%= pool.tagged_pools.size > resources_per_page ? 'true' : 'false' %>,
+    useRp: <%= pool.tagged_pools.size > resources_per_page ? 'true' : 'false' %>,
+    rp: <%= resources_per_page %>,
+    showTableToggleBtn: true,
+    onSelect: <%= on_select %>,
+    onDeselect: <%= on_deselect %>,
+    onHover: <%= on_hover %>,
+    onUnhover: <%= on_unhover %>
+    }
+    );
+    function <%= table_id %>checkbox(celDiv)
+    {
+       $(celDiv).html('<input type="checkbox" name="grid_checkbox'+$(celDiv).html()+'" class="grid_checkbox" value="'+$(celDiv).html()+'"/>');
+    }
+    function <%= table_id %>_load_widget(celDiv)
+    {
+        load_widget(celDiv, "resource");
+    };
+
+</script>
diff --git a/src/app/views/smart_pools/add_pool_dialog.rhtml b/src/app/views/smart_pools/add_pool_dialog.rhtml
new file mode 100644
index 0000000..0d8cea6
--- /dev/null
+++ b/src/app/views/smart_pools/add_pool_dialog.rhtml
@@ -0,0 +1,52 @@
+<%- content_for :title do -%>
+  Add a Hardware or Virtual Machine Pool
+<%- end -%>
+<%- content_for :description do -%>
+  Choose a Hardware or Virtual Machine Pool to add to this Smart Pool
+<%- end -%>
+
+<script type="text/javascript">
+      $(document).ready(function(){
+        $("#add_tree").asynch_treeview({
+            //animated: "normal",
+            current_pool_id:  <%=@current_pool_id%>,
+            disabled_pools: [<%=@selected_pools.join(',')%>],
+            url: "<%=  url_for :controller =>'/hardware', :action => 'json_view_tree' %>",
+            current: "disabled",
+            hardware_url: "#",
+            resource_url: "#",
+            onclick: "add_pool_to_smart_pool",
+            action_type: "javascript"
+	    })
+	});
+  function add_pool_to_smart_pool(added_pool_id)
+  {
+    $.post('<%= url_for :controller => "smart_pools", :action => "add_pools", :id => @pool %>',
+           { resource_ids: added_pool_id },
+            function(data,status){
+              grid = $("#smart_pools_grid");
+              if (grid.size()>0 && grid != null) {
+                grid.flexReload();
+              } else {
+                $tabs.tabs("load",$tabs.data('selected.tabs'));
+              }
+              $("smart_pools_grid").flexReload()
+	      jQuery(document).trigger('close.facebox');
+	      if (data.alert) {
+	        $.jGrowl(data.alert);
+              }
+             }, 'json');
+  }
+</script>
+
+<div class="dialog_tree">
+  <ul id="add_tree" class="filetree treeview-famfamfam treeview"></ul>
+</div>
+
+<div class="facebox_timfooter">
+  <div class="button">
+    <div class="button_left_grey"></div>
+    <div class="button_middle_grey"><a href="#" onclick="jQuery(document).trigger('close.facebox')">Cancel</a></div>
+    <div class="button_right_grey"></div>
+  </div>
+</div>
diff --git a/src/app/views/smart_pools/new.rhtml b/src/app/views/smart_pools/new.rhtml
new file mode 100644
index 0000000..7d488af
--- /dev/null
+++ b/src/app/views/smart_pools/new.rhtml
@@ -0,0 +1,26 @@
+<%- content_for :title do -%>
+  <%= _("Add New Smart Pool") %>
+<%- end -%>
+<%- content_for :description do -%>
+  Add a new Smart Pool.
+<%- end -%>
+
+<form method="POST" action="<%= url_for :action => 'create' %>" id="smart_pool_form" >
+  <div class="dialog_form">
+    <%= render :partial => 'form' %>
+  </div>
+  <%= popup_footer("$('#smart_pool_form').submit()", "Create Smart Pool") %>
+</form>
+
+<script type="text/javascript">
+$(function() {
+    var hwpooloptions = {
+        target:        '<%= url_for :action => 'create' %>',   // target element to update
+	dataType:      'json',
+        success:       afterSmartPool  // post-submit callback
+    };
+
+    // bind form using 'ajaxForm'
+    $('#smart_pool_form').ajaxForm(hwpooloptions);
+});
+</script>
diff --git a/src/app/views/smart_pools/show.rhtml b/src/app/views/smart_pools/show.rhtml
new file mode 100644
index 0000000..45b1753
--- /dev/null
+++ b/src/app/views/smart_pools/show.rhtml
@@ -0,0 +1,17 @@
+<div class="data_section_summary">
+
+   <div class="summary_title"><%= image_tag "icon_hdwarepool.png", :style=>"vertical-align:middle;" %> <%= @pool.name %></div><br/><br/>
+
+   <div class="summary_subtitle"><%= image_tag "icon_smry_res.png", :style=>"vertical-align:middle;" %> Resources</div><br/>
+   <div id="availability_graphs">
+      What do we show here for Smart Pools?
+   </div>
+
+   <br/><br/>
+   <div class="summary_subtitle"><%= image_tag "icon_smry_his.png", :style=>"vertical-align:middle;" %> History</div><br/>
+      What do we show here for Smart Pools?
+
+   <div class="summary_subtitle"><%= image_tag "icon_smry_perf.png", :style=>"vertical-align:middle;" %> Performance</div><br/>
+      What do we show here for Smart Pools?
+</div>
+
diff --git a/src/app/views/hardware/show_hosts.rhtml b/src/app/views/smart_pools/show_hosts.rhtml
similarity index 50%
copy from src/app/views/hardware/show_hosts.rhtml
copy to src/app/views/smart_pools/show_hosts.rhtml
index 31c575d..a4b6be7 100644
--- a/src/app/views/hardware/show_hosts.rhtml
+++ b/src/app/views/smart_pools/show_hosts.rhtml
@@ -1,89 +1,77 @@
 <div id="toolbar_nav">
  <ul>
-    <li><a href="<%= url_for :controller => 'host', :action => 'addhost', :hardware_pool_id => @pool %>" rel="facebox[.bolder]"><%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %>  Add Host</a></li>
-    <li>
-      <a id="move_link" href="#" onClick="return validate_for_move();"><%= image_tag "icon_move.png", :style=>"vertical-align:middle;" %>  Move</a>
-      <a id="move_link_hidden" href="<%= url_for :controller => 'hardware', :action => 'move', :id => @pool, :resource_type=>'hosts' %>" rel="facebox[.bolder]" style="display:none" ></a>
-    </li>
-    <% if @pool.id != HardwarePool.get_default_pool.id %>
-      <li><a href="#" onClick="remove_hosts()"><%= image_tag "icon_remove.png" %>  Remove</a></li>
-    <% end %>
+    <li><a href="<%= url_for :controller => 'host', :action => 'add_to_smart_pool', :smart_pool_id => @pool %>" rel="facebox[.bolder]"><%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %>  Add Host</a></li>
+    <li><a href="#" onClick="remove_hosts_from_smart_pool()"><%= image_tag "icon_remove.png" %>  Remove</a></li>
  </ul>
 </div>
 
 <script type="text/javascript">
-  function get_selected_hosts()
+  function get_selected_hosts_for_smart_pool()
   {
-    return get_selected_checkboxes("hosts_grid_form")
+    return get_selected_checkboxes("smart_hosts_grid_form");
   }
-  function validate_for_move()
+  function remove_hosts_from_smart_pool()
   {
-    if (validate_selected(get_selected_hosts(), 'host')) {
-      $('#move_link_hidden').click()
-    }
-  }
-  function remove_hosts()
-  {
-    hosts = get_selected_hosts()
+    var hosts = get_selected_hosts_for_smart_pool();
     if (validate_selected(hosts, "host")) {
-      $.post('<%= url_for :controller => "hardware", :action => "move_hosts", :id => @pool %>',
-             { resource_ids: hosts.toString(), target_pool_id: <%= HardwarePool.get_default_pool.id %> },
+      $.post('<%= url_for :controller => "smart_pools", :action => "remove_hosts", :id => @pool %>',
+             { resource_ids: hosts.toString() },
               function(data,status){
                 $tabs.tabs("load",$tabs.data('selected.tabs'));
 		if (data.alert) {
 		  $.jGrowl(data.alert);
                 }
-		if (hosts.indexOf($('#hosts_selection_id').html()) != -1){
-		  empty_summary('hosts_selection', 'Host')
-		}   
+		if (hosts.indexOf($('#smart_hosts_selection_id').html()) != -1){
+		  empty_summary('smart_hosts_selection', 'Host');
+		}
 
                }, 'json');
     }
   }
-  function hosts_select(selected_rows)
+  function smart_hosts_select(selected_rows)
   {
-    var selected_ids = new Array() 
-    for(i=0; i<selected_rows.length; i++) { 
-      load_widget_select(selected_rows[i]);
+    var selected_ids = new Array();
+    for(i=0; i<selected_rows.length; i++) {
       selected_ids[i] = selected_rows[i].id;
     }
     if (selected_ids.length == 1)
     {
-      $('#hosts_selection').load('<%= url_for :controller => "host", :action => "show", :id => nil %>/' + parseInt(selected_ids[0].substring(3)))
+      $('#smart_hosts_selection').load('<%= url_for :controller => "host", :action => "show", :id => nil %>/' + parseInt(selected_ids[0].substring(3)));
     }
   }
 </script>
 
 <div class="panel_header"></div>
-<% if @pool.hosts.size != 0 %>
+<% if @pool.tagged_hosts.size != 0 %>
    <div class="data_section">
-      <%= render :partial => "/host/grid", :locals => { :table_id => "hosts_grid",
+      <%= render :partial => "/host/grid", :locals => { :table_id => "smart_hosts_grid",
                                                         :hwpool => @pool,
+                                                        :pool_controller => "smart_pools",
                                                         :exclude_pool => nil,
                                                         :exclude_host => nil,
-                                                        :show_pool => false,
+                                                        :show_pool => true,
                                                         :checkboxes => true,
-                                                        :on_select => "hosts_select", 
+                                                        :on_select => "smart_hosts_select",
                                                         :on_deselect => "load_widget_deselect",
                                                         :on_hover => "load_widget_hover",
                                                         :on_unhover => "load_widget_unhover",
                                                         :is_popup => false,
                                                         :hosts_per_page => 40} %>
    </div>
-   <div class="selection_detail" id="hosts_selection">
-   	<div class="selection_left">
-	     <div>Select a host above.</div>
-        </div>
+   <div class="selection_detail" id="smart_hosts_selection">
+     <div class="selection_left">
+       <div>Select a host above.</div>
+     </div>
    </div>
 <% else %>
    <div class="data_section">
        <div class="no-grid-items">
           <%= image_tag 'no-grid-items.png', :style => 'float: left;' %>
-          
+
           <div class="no-grid-items-text">
             No hosts found in this pool. <br/><br/>
             <%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %>  
-            <a href="<%= url_for :controller => 'host', :action => 'addhost', :hardware_pool_id => @pool %>" rel="facebox[.bolder]">Add first host to this hardware pool</a>
+            <a href="<%= url_for :controller => 'host', :action => 'add_to_smart_pool', :smart_pool_id => @pool %>" rel="facebox[.bolder]">Add first host to this smart pool</a>
           </div>
        </div>
    </div>
diff --git a/src/app/views/smart_pools/show_pools.rhtml b/src/app/views/smart_pools/show_pools.rhtml
new file mode 100644
index 0000000..8e89701
--- /dev/null
+++ b/src/app/views/smart_pools/show_pools.rhtml
@@ -0,0 +1,74 @@
+<div id="toolbar_nav">
+ <ul>
+    <li><a href="<%= url_for :controller => 'smart_pools', :action => 'add_pool_dialog', :id => @pool %>" rel="facebox[.bolder]"><%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %>  Add Pool</a></li>
+    <li><a href="#" onClick="remove_pools_from_smart_pool()"><%= image_tag "icon_remove.png" %>  Remove</a></li>
+ </ul>
+</div>
+
+<script type="text/javascript">
+  function get_selected_pools_for_smart_pool()
+  {
+    return get_selected_checkboxes("smart_pools_grid_form");
+  }
+  function remove_pools_from_smart_pool()
+  {
+    var pools = get_selected_pools_for_smart_pool();
+    if (validate_selected(pools, "pool")) {
+      $.post('<%= url_for :controller => "smart_pools", :action => "remove_pools", :id => @pool %>',
+             { resource_ids: pools.toString() },
+              function(data,status){
+                $tabs.tabs("load",$tabs.data('selected.tabs'));
+		if (data.alert) {
+		  $.jGrowl(data.alert);
+                }
+		if (pools.indexOf($('#smart_pools_selection_id').html()) != -1){
+		  empty_summary('smart_pools_selection', 'Pool');
+		}
+
+               }, 'json');
+    }
+  }
+  function smart_pools_select(selected_rows)
+  {
+    var selected_ids = new Array();
+    for(i=0; i<selected_rows.length; i++) {
+      selected_ids[i] = selected_rows[i].id;
+    }
+    if (selected_ids.length == 1)
+    {
+      $('#smart_pools_selection').load('<%= url_for :controller => "search", :action => "single_result" %>',
+                { class_and_id: selected_ids[0].substring(3)});
+    }
+  }
+</script>
+
+<div class="panel_header"></div>
+<% if @pool.tagged_pools.size != 0 %>
+   <div class="data_section">
+      <%= render :partial => "/smart_pools/pools_grid", :locals => { :table_id => "smart_pools_grid",
+                                                        :pool => @pool,
+                                                        :pool_controller => "smart_pools",
+                                                        :checkboxes => true,
+                                                        :on_select => "smart_pools_select",
+                                                        :on_deselect => false,
+                                                        :on_hover => false,
+                                                        :on_unhover => false} %>
+   </div>
+   <div class="selection_detail" id="smart_pools_selection">
+     <div class="selection_left">
+       <div>Select a pool above.</div>
+     </div>
+   </div>
+<% else %>
+   <div class="data_section">
+       <div class="no-grid-items">
+          <%= image_tag 'no-grid-items.png', :style => 'float: left;' %>
+
+          <div class="no-grid-items-text">
+            No pools found in this pool. <br/><br/>
+            <%= image_tag "icon_addpool.png", :style=>"vertical-align:middle;" %>  
+            <a href="<%= url_for :controller => 'pool', :action => 'add_to_smart_pool', :smart_pool_id => @pool %>" rel="facebox[.bolder]">Add first Pool to this smart pool</a>
+          </div>
+       </div>
+   </div>
+<% end %>
diff --git a/src/app/views/smart_pools/show_storage.rhtml b/src/app/views/smart_pools/show_storage.rhtml
new file mode 100644
index 0000000..7cf425a
--- /dev/null
+++ b/src/app/views/smart_pools/show_storage.rhtml
@@ -0,0 +1,72 @@
+<div id="toolbar_nav">
+<ul>
+    <li><a href="<%= url_for :controller => 'storage', :action => 'add_to_smart_pool', :smart_pool_id => @pool %>" rel="facebox[.bolder]"><%= image_tag "icon_addstorage.png", :style=>"vertical-align:middle;" %>  Add Storage Pool</a></li>
+    <li><a href="#" onClick="remove_storage_from_smart_pool()"><%= image_tag "icon_remove.png" %>  Remove</a></li>
+  </ul>
+</div>
+
+<script type="text/javascript">
+  function get_selected_storage_for_smart_pool()
+  {
+    return get_selected_checkboxes("smart_storage_grid_form");
+  }
+  function remove_storage_from_smart_pool()
+  {
+    var storage = get_selected_storage_for_smart_pool();
+    if (validate_selected(storage, "storage pool")) {
+      $.post('<%= url_for :controller => "smart_pools", :action => "remove_storage", :id => @pool %>',
+             { resource_ids: storage.toString() },
+              function(data,status){
+                $tabs.tabs("load",$tabs.data('selected.tabs'));
+		if (data.alert) {
+		  $.jGrowl(data.alert);
+                }
+		if (storage.indexOf($('#smart_storage_selection_id').html()) != -1){
+		  empty_summary('smart_storage_selection', 'Storage Pool');
+		}
+               }, 'json');
+    }
+  }
+  function smart_storage_select(selected_rows)
+  {
+    var selected_ids = new Array() ;
+    for(i=0; i<selected_rows.length; i++) {
+      selected_ids[i] = selected_rows[i].id;
+    }
+    if (selected_ids.length == 1)
+    {
+      $('#smart_storage_selection').load('<%= url_for :controller => "storage", :action => "show" %>',
+                { id: parseInt(selected_ids[0].substring(3))});
+    }
+  }
+
+</script>
+<div class="panel_header"></div>
+<% if @pool.tagged_storage_pools.size != 0 %>
+  <div class="data_section">
+       <%= render :partial => "/storage/grid", :locals => { :table_id => "smart_storage_grid",
+                                                            :hwpool => @pool,
+                                                            :pool_controller => "smart_pools",
+                                                            :exclude_pool => nil,
+                                                            :on_select => "smart_storage_select",
+                                                            :is_popup => false} %>
+  </div>
+
+  <div class="selection_detail" id="smart_storage_selection">
+    <div class="selection_left">
+      <div>Select a storage pool.</div>
+    </div>
+  </div>
+<% else %>
+   <div class="data_section">
+       <div class="no-grid-items">
+          <%= image_tag 'no-grid-items.png', :style => 'float: left;' %>
+
+          <div class="no-grid-items-text">
+            No storage Pools found in this pool. <br/><br/>
+            <%= image_tag "icon_addstorage.png", :style=>"vertical-align:middle;" %>  
+            <a href="<%= url_for :controller => 'storage', :action => 'add_to_smart_pool', :smart_pool_id => @pool %>" rel="facebox[.bolder]">Add first storage volume to this smart pool</a>
+          </div>
+       </div>
+   </div>
+<% end %>
diff --git a/src/app/views/smart_pools/show_users.rhtml b/src/app/views/smart_pools/show_users.rhtml
new file mode 100644
index 0000000..7d1efb8
--- /dev/null
+++ b/src/app/views/smart_pools/show_users.rhtml
@@ -0,0 +1,2 @@
+  <%= render :partial => "/user/show", :locals => { :parent_controller => "smart_pools",
+                                                    :pool => @pool } %>
diff --git a/src/app/views/smart_pools/show_vms.rhtml b/src/app/views/smart_pools/show_vms.rhtml
new file mode 100644
index 0000000..e56600b
--- /dev/null
+++ b/src/app/views/smart_pools/show_vms.rhtml
@@ -0,0 +1,77 @@
+<div id="toolbar_nav">
+ <ul>
+    <li><a href="<%= url_for :controller => 'vm', :action => 'add_to_smart_pool', :smart_pool_id => @pool %>" rel="facebox[.bolder]"><%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %>  Add Virtual Machine</a></li>
+    <li><a href="#" onClick="remove_vms_from_smart_pool()"><%= image_tag "icon_remove.png" %>  Remove</a></li>
+ </ul>
+</div>
+
+<script type="text/javascript">
+  function get_selected_vms_for_smart_pool()
+  {
+    return get_selected_checkboxes("smart_vms_grid_form");
+  }
+  function remove_vms_from_smart_pool()
+  {
+    var vms = get_selected_vms_for_smart_pool();
+    if (validate_selected(vms, "vm")) {
+      $.post('<%= url_for :controller => "smart_pools", :action => "remove_vms", :id => @pool %>',
+             { resource_ids: vms.toString() },
+              function(data,status){
+                $tabs.tabs("load",$tabs.data('selected.tabs'));
+		if (data.alert) {
+		  $.jGrowl(data.alert);
+                }
+		if (vms.indexOf($('#smart_vms_selection_id').html()) != -1){
+		  empty_summary('smart_vms_selection', 'Vm');
+		}
+
+               }, 'json');
+    }
+  }
+  function smart_vms_select(selected_rows)
+  {
+    var selected_ids = new Array();
+    for(i=0; i<selected_rows.length; i++) {
+      selected_ids[i] = selected_rows[i].id;
+    }
+    if (selected_ids.length == 1)
+    {
+      $('#smart_vms_selection').load('<%= url_for :controller => "vm", :action => "show", :id => nil %>/' + parseInt(selected_ids[0].substring(3)));
+    }
+  }
+</script>
+
+<div class="panel_header"></div>
+<% if @pool.tagged_vms.size != 0 %>
+   <div class="data_section">
+      <%= render :partial => "/vm/grid", :locals => { :table_id => "smart_vms_grid",
+                                                        :pool => @pool,
+                                                        :pool_controller => "smart_pools",
+                                                        :exclude_pool => nil,
+                                                        :show_pool => true,
+                                                        :checkboxes => true,
+                                                        :on_select => "smart_vms_select",
+                                                        :on_deselect => "load_widget_deselect",
+                                                        :on_hover => "load_widget_hover",
+                                                        :on_unhover => "load_widget_unhover",
+                                                        :is_popup => false,
+                                                        :vms_per_page => 40} %>
+   </div>
+   <div class="selection_detail" id="smart_vms_selection">
+     <div class="selection_left">
+       <div>Select a vm above.</div>
+     </div>
+   </div>
+<% else %>
+   <div class="data_section">
+       <div class="no-grid-items">
+          <%= image_tag 'no-grid-items.png', :style => 'float: left;' %>
+
+          <div class="no-grid-items-text">
+            No vms found in this pool. <br/><br/>
+            <%= image_tag "icon_addvm.png", :style=>"vertical-align:middle;" %>  
+            <a href="<%= url_for :controller => 'vm', :action => 'add_to_smart_pool', :smart_pool_id => @pool %>" rel="facebox[.bolder]">Add first VM to this smart pool</a>
+          </div>
+       </div>
+   </div>
+<% end %>
diff --git a/src/app/views/storage/_grid.rhtml b/src/app/views/storage/_grid.rhtml
index c36f4d3..c8876bb 100644
--- a/src/app/views/storage/_grid.rhtml
+++ b/src/app/views/storage/_grid.rhtml
@@ -1,4 +1,12 @@
-<% storage_per_page = 40 %>
+<% storage_per_page = 40 unless (defined? storage_per_page) and !(storage_per_page.nil?) %>
+<% pool_controller = 'hardware' unless (defined? pool_controller) and !(pool_controller.nil?) %>
+<% if (hwpool.nil? or
+       ((hwpool.is_a? HardwarePool) and (hwpool.storage_pools.size > storage_per_page)) or
+       ((hwpool.is_a? SmartPool) and (hwpool.tagged_storage_pools.size > storage_per_page)))
+     usepager = 'true'
+   else
+     usepager = 'false'
+   end %>
 
 <div id="<%= table_id %>_div">
 <form id="<%= table_id %>_form">
@@ -9,7 +17,10 @@
     $("#<%= table_id %>").flexigrid
     (
     {
-    url: '<%=  url_for :controller => "hardware", :action => "storage_pools_json", :id => (hwpool.nil? ? nil : hwpool.id), :exclude_pool => exclude_pool %>',
+    url: '<%=  url_for :controller => pool_controller,
+                       :action => "storage_pools_json",
+                       :id => (hwpool.nil? ? nil : hwpool.id),
+                       :exclude_pool => exclude_pool %>',
     dataType: 'json',
     <% if is_popup %>
         width: 700,
@@ -23,8 +34,8 @@
         ],
     sortname: "ip_addr",
     sortorder: "asc",
-    usepager: <%= (hwpool.nil? or hwpool.storage_pools.size > storage_per_page) ? 'true' : 'false' %>,
-    useRp: <%= (hwpool.nil? or hwpool.storage_pools.size > storage_per_page) ? 'true' : 'false' %>,
+    usepager: <%= usepager %>,
+    useRp: <%= usepager %>,
     rp: <%= storage_per_page %>,
     showTableToggleBtn: true,
     onSelect: <%= on_select %>
diff --git a/src/app/views/storage/add_to_smart_pool.rhtml b/src/app/views/storage/add_to_smart_pool.rhtml
new file mode 100644
index 0000000..2eedae3
--- /dev/null
+++ b/src/app/views/storage/add_to_smart_pool.rhtml
@@ -0,0 +1,22 @@
+<%- content_for :title do -%>
+  <%= _("Add Storage Pool to Smart Pool") %>
+<%- end -%>
+<%- content_for :description do -%>
+  Select storage pools from the list below to add to the <%= @pool.name %> smart pool.</a>
+<%- end -%>
+<div id="dialog-content-area">
+<div class="dialog_body_small">
+<div class="panel_header"></div>
+  <%= render :partial => "/storage/grid", :locals => { :table_id => "add_smart_storage_grid",
+             :hwpool => nil,
+             :pool_controller => "smart_pools",
+             :exclude_pool => @pool.id,
+             :on_select => false,
+             :is_popup => true} %>
+</div>
+
+<%= popup_footer("add_storage_to_smart_pool('#{url_for :controller => "smart_pools",
+                                                     :action => "add_storage",
+                                                     :id => @pool}')",
+                 "Add Storage Pools") %>
+</div>
diff --git a/src/app/views/user/_show.rhtml b/src/app/views/user/_show.rhtml
index 916afe8..5b3ffb7 100644
--- a/src/app/views/user/_show.rhtml
+++ b/src/app/views/user/_show.rhtml
@@ -12,7 +12,7 @@
   }
   function delete_users()
   {
-    permissions = get_selected_users();
+    var permissions = get_selected_users();
     if (validate_selected(permissions, "user")) {
       $.post('<%= url_for :controller => "permission", :action => "delete", :id => pool.id %>',
            { permission_ids: permissions.toString() },
@@ -26,7 +26,7 @@
   }
   function update_users(role)
   {
-    permissions = get_selected_users()
+    var permissions = get_selected_users();
     if (validate_selected(permissions, "users")) {
       $.post('<%= url_for :controller => "permission", :action => "update_roles" %>',
              { permission_ids: permissions.toString(), user_role: role },
diff --git a/src/app/views/vm/_grid.rhtml b/src/app/views/vm/_grid.rhtml
index c56e6b8..a322ea3 100644
--- a/src/app/views/vm/_grid.rhtml
+++ b/src/app/views/vm/_grid.rhtml
@@ -1,42 +1,56 @@
 <%= render :partial => 'graph/load_graph.rhtml' %>
-<% vms_per_page = 10 %>
+<% pool_controller = 'resources' unless (defined? pool_controller) and !(pool_controller.nil?) %>
+<% vms_per_page = 40 unless (defined? vms_per_page) and !(vms_per_page.nil?) %>
+<% if (pool.nil? or
+       ((pool.is_a? VmResourcePool) and (pool.vms.size > vms_per_page)) or
+       ((pool.is_a? SmartPool) and (pool.tagged_vms.size > vms_per_page)))
+     usepager = 'true'
+   else
+     usepager = 'false'
+   end %>
 <div id="<%= table_id %>_div">
 <form id="<%= table_id %>_form">
 <table id="<%= table_id %>" style="display:none"></table>
 </form>
 </div>
 <script type="text/javascript">
-	$("#<%= table_id %>").flexigrid
-	(
-	{
-	url: '<%=  url_for :controller => "resources", :action => "vms_json", :id => pool.id %>',
-	dataType: 'json',
-	colModel : [
-		{display: '', name : 'id', width : 20, sortable : false, align: 'left', process: <%= table_id %>checkbox},
-		{display: 'Description', name : 'description', width : 180, sortable : true, align: 'left'},
-	        {display: 'UUID', name : 'uuid', width : 180, sortable : true, align: 'left'},
-		{display: 'CPUs', name : 'num_vcpus_allocated', width : 40, sortable : true, align: 'left'},
-		{display: 'Memory (MB)', name : 'memory_allocated', width : 60, sortable : true, align: 'right'},
-		{display: 'vNIC Mac Addr', name : 'vnic_mac_addr', width : 60, sortable : true, align: 'right'},
-		{display: 'State', name : 'state', width : 50, sortable : true, align: 'right'},
+    $("#<%= table_id %>").flexigrid
+    (
+    {
+    url: '<%=  url_for :controller => pool_controller,
+                       :action => "vms_json",
+                       :id => (pool.nil? ? nil : pool.id),
+                       :exclude_pool => exclude_pool %>',
+    dataType: 'json',
+    <% if is_popup %>
+        width: 700,
+    <% end %>
+    colModel : [
+        {display: '', name : 'id', width : 20, sortable : false, align: 'left', process: <%= table_id %>checkbox},
+        {display: 'Description', name : 'description', width : 180, sortable : true, align: 'left'},
+        {display: 'UUID', name : 'uuid', width : 180, sortable : true, align: 'left'},
+        {display: 'CPUs', name : 'num_vcpus_allocated', width : 40, sortable : true, align: 'left'},
+        {display: 'Memory (MB)', name : 'memory_allocated', width : 60, sortable : true, align: 'right'},
+        {display: 'vNIC Mac Addr', name : 'vnic_mac_addr', width : 60, sortable : true, align: 'right'},
+        {display: 'State', name : 'state', width : 50, sortable : true, align: 'right'},
         {display: 'Load', name : 'load', width: 180, sortable : false, align: 'left', process: <%= table_id %>_load_widget }
-		],
-	sortname: "description",
-	sortorder: "asc",
-	usepager: <%= pool.vms.size > vms_per_page ? 'true' : 'false' %>,
-    useRp: <%= pool.vms.size > vms_per_page ? 'true' : 'false' %>,
-	rp: <%= vms_per_page %>,
-	showTableToggleBtn: true,
-	onSelect: <%= on_select %>,
+        ],
+    sortname: "description",
+    sortorder: "asc",
+    usepager: <%= usepager %>,
+    useRp: <%= usepager %>,
+    rp: <%= vms_per_page %>,
+    showTableToggleBtn: true,
+    onSelect: <%= on_select %>,
     onDeselect: <%= on_deselect %>,
     onHover: <%= on_hover %>,
     onUnhover: <%= on_unhover %>
-	}
-	);   
-	function <%= table_id %>checkbox(celDiv)
-	{
-	       $(celDiv).html('<input type="checkbox" name="grid_checkbox'+$(celDiv).html()+'" class="grid_checkbox" value="'+$(celDiv).html()+'"/>');
-	} 
+    }
+    );
+    function <%= table_id %>checkbox(celDiv)
+    {
+       $(celDiv).html('<input type="checkbox" name="grid_checkbox'+$(celDiv).html()+'" class="grid_checkbox" value="'+$(celDiv).html()+'"/>');
+    }
     function <%= table_id %>_load_widget(celDiv)
     {
         load_widget(celDiv, "vm");
diff --git a/src/app/views/vm/add_to_smart_pool.rhtml b/src/app/views/vm/add_to_smart_pool.rhtml
new file mode 100644
index 0000000..cdfe92d
--- /dev/null
+++ b/src/app/views/vm/add_to_smart_pool.rhtml
@@ -0,0 +1,27 @@
+<%- content_for :title do -%>
+  <%= _("Add Vm to Smart Pool") %>
+<%- end -%>
+<%- content_for :description do -%>
+  Select vms from the list below to add to the <%= @pool.name %> smart pool.</a>
+<%- end -%>
+<div id="dialog-content-area">
+<div class="dialog_body_small">
+<div class="panel_header"></div>
+  <%= render :partial => "/vm/grid", :locals => { :table_id => "add_smart_vms_grid",
+             :pool => nil,
+             :pool_controller => "smart_pools",
+             :exclude_pool => @pool.id,
+             :checkboxes => true,
+             :on_select => false,
+             :on_deselect => false,
+             :on_hover => false,
+             :on_unhover => false,
+             :is_popup => true,
+             :vms_per_page => 40} %>
+</div>
+
+<%= popup_footer("add_vms_to_smart_pool('#{url_for :controller => "smart_pools",
+                                                     :action => "add_vms",
+                                                     :id => @pool}')",
+                 "Add Vms") %>
+</div>
diff --git a/src/db/migrate/017_add_smart_pools.rb b/src/db/migrate/017_add_smart_pools.rb
index 6d83c02..5550a89 100644
--- a/src/db/migrate/017_add_smart_pools.rb
+++ b/src/db/migrate/017_add_smart_pools.rb
@@ -47,7 +47,7 @@ class AddSmartPools < ActiveRecord::Migration
             new_permission = Permission.new({:pool_id     => dir_root.id,
                                              :uid         => permission.uid,
                                              :user_role   => permission.user_role})
-            new_permission.save!
+            new_permission.save_with_new_children
           end
         end
       end
diff --git a/src/public/javascripts/jquery-treeview/jquery.treeview.async.js b/src/public/javascripts/jquery-treeview/jquery.treeview.async.js
index b10a130..4dacda6 100644
--- a/src/public/javascripts/jquery-treeview/jquery.treeview.async.js
+++ b/src/public/javascripts/jquery-treeview/jquery.treeview.async.js
@@ -43,7 +43,7 @@ function load(settings, params, child, container) {
    		        } else {
 			    span_onclick = ""
 		        }
-                        if (settings.current_pool_id==this.id) {
+                        if (settings.current_pool_id==this.id || !((settings.disabled_pools == undefined) || ($.inArray(this.id,settings.disabled_pools)==-1))) {
                           current.html("<span class=\"" + settings.current_class + ">" + this.text  + "</span>")
                             .appendTo(parent);
                         } else {
diff --git a/src/public/javascripts/jquery.ovirt.treeview.js b/src/public/javascripts/jquery.ovirt.treeview.js
index 16cf260..bb41667 100644
--- a/src/public/javascripts/jquery.ovirt.treeview.js
+++ b/src/public/javascripts/jquery.ovirt.treeview.js
@@ -21,10 +21,18 @@ function load(settings, params, child, container) {
                             settings.link_to=settings.hardware_url 
                             settings.span_class="folder";
                             settings.current_class = settings.current + "_folder";
-                        } else {
+                        } else if (this.type=="VmResourcePool") {
                             settings.link_to=settings.resource_url;
                             settings.span_class="file";
                             settings.current_class = settings.current + "_file";
+                        } else if (this.type=="SmartPool") {
+                            settings.link_to=settings.smart_url;
+                            settings.span_class="file";
+                            settings.current_class = settings.current + "_file";
+                        } else {
+                            settings.link_to="";
+                            settings.span_class="file";
+                            settings.current_class = settings.current + "_file";
                         }   
 			var span_onclick;
 			var current = $("<li/>").attr("id", this.id || "");
@@ -64,7 +72,7 @@ function load(settings, params, child, container) {
 			}
 		} 
                 $(container).find('li').remove();
-                createNode.call(response, child);                
+                $.each(response, createNode, [child]);
                 $(container).ovirt_treeview({add: child});
                 for (var i = 0; i < selectedNodes.length; i++){
                   $('#test-tree li#' + selectedNodes[i] +' > div').click();
diff --git a/src/public/javascripts/ovirt.js b/src/public/javascripts/ovirt.js
index af0b9f6..470a53a 100644
--- a/src/public/javascripts/ovirt.js
+++ b/src/public/javascripts/ovirt.js
@@ -42,7 +42,7 @@ function add_hosts(url)
       $.post(url,
              { resource_ids: hosts.toString() },
               function(data,status){ 
-                jQuery(document).trigger('close.facebox');
+                $(document).trigger('close.facebox');
 	        grid = $("#hosts_grid");
                 if (grid.size()>0 && grid != null) {
                   grid.flexReload();
@@ -62,7 +62,7 @@ function add_storage(url)
       $.post(url,
              { resource_ids: storage.toString() },
               function(data,status){;
-                jQuery(document).trigger('close.facebox');
+                $(document).trigger('close.facebox');
 	        grid = $("#storage_grid");
                 if (grid.size()>0 && grid != null) {
                   grid.flexReload();
@@ -75,6 +75,66 @@ function add_storage(url)
                }, 'json');
     }
 }
+function add_hosts_to_smart_pool(url)
+{
+    hosts= get_selected_checkboxes("add_smart_hosts_grid_form");
+    if (validate_selected(hosts, "host")) {
+      $.post(url,
+             { resource_ids: hosts.toString() },
+              function(data,status){
+                $(document).trigger('close.facebox');
+	        grid = $("#smart_hosts_grid");
+                if (grid.size()>0 && grid != null) {
+                  grid.flexReload();
+                } else {
+		  $tabs.tabs("load",$tabs.data('selected.tabs'));
+                }
+		if (data.alert) {
+		  $.jGrowl(data.alert);
+                }
+               }, 'json');
+    }
+}
+function add_storage_to_smart_pool(url)
+{
+    storage= get_selected_checkboxes("add_smart_storage_grid_form");
+    if (validate_selected(storage, "storage pool")) {
+      $.post(url,
+             { resource_ids: storage.toString() },
+              function(data,status){
+                $(document).trigger('close.facebox');
+	        grid = $("#smart_storage_grid");
+                if (grid.size()>0 && grid != null) {
+                  grid.flexReload();
+                } else {
+		  $tabs.tabs("load",$tabs.data('selected.tabs'));
+                }
+		if (data.alert) {
+		  $.jGrowl(data.alert);
+                }
+               }, 'json');
+    }
+}
+function add_vms_to_smart_pool(url)
+{
+    vms= get_selected_checkboxes("add_smart_vms_grid_form");
+    if (validate_selected(vms, "vm")) {
+      $.post(url,
+             { resource_ids: vms.toString() },
+              function(data,status){
+                $(document).trigger('close.facebox');
+	        grid = $("#smart_vms_grid");
+                if (grid.size()>0 && grid != null) {
+                  grid.flexReload();
+                } else {
+		  $tabs.tabs("load",$tabs.data('selected.tabs'));
+                }
+		if (data.alert) {
+		  $.jGrowl(data.alert);
+                }
+               }, 'json');
+    }
+}
 // deal with ajax form response, filling in validation messages where required.
 function ajax_validation(response, status)
 {
@@ -102,7 +162,7 @@ function ajax_validation(response, status)
 function afterHwPool(response, status){
     ajax_validation(response, status);
     if (response.success) {
-      jQuery(document).trigger('close.facebox');
+      $(document).trigger('close.facebox');
       // FIXME do we need to reload the tree here
 
       // this is for reloading the host/storage grid when 
@@ -128,7 +188,7 @@ function afterHwPool(response, status){
 function afterVmPool(response, status){
     ajax_validation(response, status);
     if (response.success) {
-      jQuery(document).trigger('close.facebox');
+      $(document).trigger('close.facebox');
       grid = $("#vmpools_grid");
       if (grid.size()>0 && grid != null) {
         grid.flexReload();
@@ -137,10 +197,16 @@ function afterVmPool(response, status){
       }
     }
 }
+function afterSmartPool(response, status){
+    ajax_validation(response, status);
+    if (response.success) {
+      $(document).trigger('close.facebox');
+    }
+}
 function afterStoragePool(response, status){
     ajax_validation(response, status);
     if (response.success) {
-      jQuery(document).trigger('close.facebox');
+      $(document).trigger('close.facebox');
       grid = $("#storage_grid");
       if (grid.size()>0 && grid != null) {
         grid.flexReload();
@@ -152,7 +218,7 @@ function afterStoragePool(response, status){
 function afterPermission(response, status){
     ajax_validation(response, status);
     if (response.success) {
-      jQuery(document).trigger('close.facebox');
+      $(document).trigger('close.facebox');
       grid = $("#users_grid");
       if (grid.size()>0 && grid!= null) {
         grid.flexReload();
@@ -164,7 +230,7 @@ function afterPermission(response, status){
 function afterVm(response, status){
     ajax_validation(response, status);
     if (response.success) {
-      jQuery(document).trigger('close.facebox');
+      $(document).trigger('close.facebox');
       grid = $("#vms_grid");
       if (grid.size()>0 && grid != null) {
         grid.flexReload();
@@ -212,7 +278,23 @@ function delete_or_remove_storage()
     } else if (selected[0].value == "delete") {
         delete_storage();
     }
-    jQuery(document).trigger('close.facebox');
+    $(document).trigger('close.facebox');
+}
+function delete_pool(delete_url, id)
+{
+  $(document).trigger('close.facebox');
+
+  if (delete_url==='') {
+    $.jGrowl("Invalid Pool Type");
+    return;
+  }
+  $.post(delete_url,
+         {id: id},
+          function(data,status){
+            if (data.alert) {
+              $.jGrowl(data.alert);
+            }
+           }, 'json');
 }
 
 
-- 
1.5.5.1




More information about the ovirt-devel mailing list