[Ovirt-devel] [PATCH] added VM-level migration support to the WUI. Still no back end bits here, though.

Scott Seago sseago at redhat.com
Tue Jul 15 15:28:40 UTC 2008


Signed-off-by: Scott Seago <sseago at redhat.com>
---
 wui/src/app/controllers/hardware_controller.rb  |   18 ++++--
 wui/src/app/controllers/host_controller.rb      |   11 +++
 wui/src/app/controllers/resources_controller.rb |   25 -------
 wui/src/app/controllers/vm_controller.rb        |   13 +++-
 wui/src/app/models/vm.rb                        |   31 ++++++---
 wui/src/app/models/vm_task.rb                   |   70 +++++++++++++++-----
 wui/src/app/views/hardware/show_hosts.rhtml     |    5 +-
 wui/src/app/views/hardware/show_storage.rhtml   |    2 +-
 wui/src/app/views/host/_grid.rhtml              |   15 +++--
 wui/src/app/views/host/addhost.html.erb         |    5 +-
 wui/src/app/views/host/quick_summary.rhtml      |    1 +
 wui/src/app/views/storage/_grid.rhtml           |    4 +-
 wui/src/app/views/storage/add.rhtml             |    2 +-
 wui/src/app/views/vm/migrate.rhtml              |   81 +++++++++++++++++++++++
 wui/src/app/views/vm/show.rhtml                 |   15 +++-
 wui/src/public/javascripts/flexigrid.js         |    4 +-
 wui/src/public/javascripts/ovirt.js             |    2 +-
 17 files changed, 230 insertions(+), 74 deletions(-)
 create mode 100644 wui/src/app/views/host/quick_summary.rhtml
 create mode 100644 wui/src/app/views/vm/migrate.rhtml

diff --git a/wui/src/app/controllers/hardware_controller.rb b/wui/src/app/controllers/hardware_controller.rb
index 4175fd8..926b6c8 100644
--- a/wui/src/app/controllers/hardware_controller.rb
+++ b/wui/src/app/controllers/hardware_controller.rb
@@ -112,7 +112,12 @@ class HardwareController < ApplicationController
   end
 
   def hosts_json
-    if params[:id]
+    if params[:exclude_host]
+      pre_json
+      hosts = @pool.hosts
+      find_opts = {:conditions => ["id != ?", params[:exclude_host]]}
+      include_pool = false
+    elsif params[:id]
       pre_json
       hosts = @pool.hosts
       find_opts = {}
@@ -120,14 +125,17 @@ class HardwareController < ApplicationController
     else
       # FIXME: no permissions or usage checks here yet
       # filtering on which pool to exclude
-      id = params[:exclude_id]
+      id = params[:exclude_pool]
       hosts = Host
       find_opts = {:include => :hardware_pool, 
         :conditions => ["pools.id != ?", id]}
       include_pool = true
     end
-    attr_list = [:id, :hostname, :uuid, :hypervisor_type, :num_cpus, :cpu_speed, :arch, :memory_in_mb, :status_str, :id]
-    attr_list.insert(2, [:hardware_pool, :name]) if include_pool
+    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, :id]
     json_list(hosts, attr_list, [:all], find_opts)
   end
 
@@ -152,7 +160,7 @@ class HardwareController < ApplicationController
     else
       # FIXME: no permissions or usage checks here yet
       # filtering on which pool to exclude
-      id = params[:exclude_id]
+      id = params[:exclude_pool]
       storage_pools = StoragePool
       find_opts = {:include => :hardware_pool, 
         :conditions => ["pools.id != ?", id]}
diff --git a/wui/src/app/controllers/host_controller.rb b/wui/src/app/controllers/host_controller.rb
index 20571d7..4e4375a 100644
--- a/wui/src/app/controllers/host_controller.rb
+++ b/wui/src/app/controllers/host_controller.rb
@@ -44,6 +44,17 @@ class HostController < ApplicationController
     render :layout => 'selection'    
   end
 
+  def quick_summary
+    pre_show
+    set_perms(@perm_obj)
+    unless @can_view
+      flash[:notice] = 'You do not have permission to view this host: redirecting to top level'
+      #perm errors for ajax should be done differently
+      redirect_to :controller => 'dashboard', :action => 'list'
+    end
+    render :layout => false
+  end
+
   # retrieves data used by snapshot graphs
   def snapshot_graph
   end
diff --git a/wui/src/app/controllers/resources_controller.rb b/wui/src/app/controllers/resources_controller.rb
index 694ef74..ca10960 100644
--- a/wui/src/app/controllers/resources_controller.rb
+++ b/wui/src/app/controllers/resources_controller.rb
@@ -184,31 +184,6 @@ class ResourcesController < ApplicationController
       @failure_list = []
     end
     render :layout => 'confirmation'    
-        
-    #if params[:vm_actions][:vms]
-    #  vms = params[:vm_actions][:vms]
-    #  if params[:vm_actions][VmTask::ACTION_START_VM]
-    #    flash[:notice] = "Starting Machines #{vms.join(',')}."
-    #  elsif params[:vm_actions][VmTask::ACTION_SHUTDOWN_VM]
-    #    flash[:notice] = "Stopping Machines #{vms.join(',')}."
-    #  elsif params[:vm_actions][:other_actions]
-    #    case params[:vm_actions][:other_actions]
-    #    when VmTask::ACTION_SHUTDOWN_VM then flash[:notice] = "Stopping Machines #{vms.join(',')}."
-    #    when VmTask::ACTION_START_VM then flash[:notice] = "Starting Machines #{vms.join(',')}."
-    #    when VmTask::ACTION_SUSPEND_VM then flash[:notice] = "Suspending Machines #{vms.join(',')}."
-    #    when VmTask::ACTION_RESUME_VM then flash[:notice] = "Resuming Machines #{vms.join(',')}."
-    #    when VmTask::ACTION_SAVE_VM then flash[:notice] = "Saving Machines #{vms.join(',')}."
-    #    when VmTask::ACTION_RESTORE_VM then flash[:notice] = "Restoring Machines #{vms.join(',')}."
-    #    when "destroy" then flash[:notice] = "Destroying Machines #{vms.join(',')}."
-    #    else
-    #      flash[:notice] = 'No Action Chosen.'
-    #    end
-    #  else
-    #    flash[:notice] = 'No Action Chosen.'
-    #  end
-    #else
-    #  flash[:notice] = 'No Virtual Machines Selected.'
-    #end
   end
 
   protected
diff --git a/wui/src/app/controllers/vm_controller.rb b/wui/src/app/controllers/vm_controller.rb
index b9156d2..4f9962d 100644
--- a/wui/src/app/controllers/vm_controller.rb
+++ b/wui/src/app/controllers/vm_controller.rb
@@ -26,7 +26,7 @@ class VmController < ApplicationController
 
   def show
     set_perms(@perm_obj)
-    @actions = @vm.get_action_and_label_list
+    @actions = @vm.get_action_hash(@user)
     unless @can_view
       flash[:notice] = 'You do not have permission to view this vm: redirecting to top level'
       redirect_to :controller => 'resources', :controller => 'dashboard'
@@ -149,8 +149,9 @@ class VmController < ApplicationController
 
   def vm_action
     vm_action = params[:vm_action]
+    data = params[:vm_action_data]
     begin
-      if @vm.queue_action(get_login_user, vm_action)
+      if @vm.queue_action(get_login_user, vm_action, data)
         render :json => { :object => "vm", :success => true, :alert => "#{vm_action} was successfully queued." }
       else
         render :json => { :object => "vm", :success => false, :alert => "#{vm_action} is an invalid action." }
@@ -171,6 +172,14 @@ class VmController < ApplicationController
     end
   end
 
+  def migrate
+    @vm = Vm.find(params[:id])
+    @perm_obj = @vm.get_hardware_pool
+    @redir_obj = @vm
+    @current_pool_id=@vm.vm_resource_pool.id
+    authorize_admin
+    render :layout => 'popup'
+  end
 
   def console
     @show_vnc_error = "Console is unavailable for VM #{@vm.description}" unless @vm.has_console
diff --git a/wui/src/app/models/vm.rb b/wui/src/app/models/vm.rb
index 617512e..b607886 100644
--- a/wui/src/app/models/vm.rb
+++ b/wui/src/app/models/vm.rb
@@ -22,7 +22,7 @@ require 'util/ovirt'
 class Vm < ActiveRecord::Base
   belongs_to :vm_resource_pool
   belongs_to :host
-  has_many :tasks, :class_name => "VmTask", :dependent => :destroy, :order => "id DESC" do
+  has_many :tasks, :class_name => "VmTask", :dependent => :destroy, :order => "id ASC" do
     def queued
       find(:all, :conditions=>{:state=>Task::STATE_QUEUED})
     end
@@ -58,6 +58,9 @@ class Vm < ActiveRecord::Base
   STATE_SAVING         = "saving"
   STATE_SAVED          = "saved"
   STATE_RESTORING      = "restoring"
+
+  STATE_MIGRATING      = "migrating"
+
   STATE_CREATE_FAILED  = "create_failed"
   STATE_INVALID        = "invalid"
 
@@ -68,7 +71,8 @@ class Vm < ActiveRecord::Base
                           STATE_SUSPENDING,
                           STATE_RESUMING,
                           STATE_SAVING,
-                          STATE_RESTORING]
+                          STATE_RESTORING,
+                          STATE_MIGRATING]
 
   EFFECTIVE_STATE = {  STATE_PENDING       => STATE_PENDING,
                        STATE_UNREACHABLE   => STATE_UNREACHABLE,
@@ -83,9 +87,15 @@ class Vm < ActiveRecord::Base
                        STATE_SAVING        => STATE_SAVED,
                        STATE_SAVED         => STATE_SAVED,
                        STATE_RESTORING     => STATE_RUNNING,
+                       STATE_MIGRATING     => STATE_RUNNING,
                        STATE_CREATE_FAILED => STATE_CREATE_FAILED}
   TASK_STATE_TRANSITIONS = []
 
+  def get_hardware_pool
+    pool = vm_resource_pool
+    pool = pool.get_hardware_pool if pool
+    pool
+  end
   def storage_volume_ids
     storage_volumes.collect {|x| x.id }
   end
@@ -126,9 +136,9 @@ class Vm < ActiveRecord::Base
     RUNNING_STATES.include?(get_pending_state)
   end
 
-  def get_action_list
+  def get_action_list(user=nil)
     # return empty list rather than nil
-    return_val = VmTask::VALID_ACTIONS_PER_VM_STATE[get_pending_state] || []
+    return_val = VmTask.valid_actions_for_vm_state(get_pending_state, self, user) || []
     # filter actions based on quota
     unless resources_for_start?
       return_val = return_val - [VmTask::ACTION_START_VM, VmTask::ACTION_RESTORE_VM]
@@ -136,10 +146,12 @@ class Vm < ActiveRecord::Base
     return_val
   end
 
-  def get_action_and_label_list
-    get_action_list.collect do |action|
-      VmTask.label_and_action(action)
+  def get_action_hash(user=nil)
+    actions = {}
+    get_action_list(user).each do |action|
+      actions[action] = VmTask::ACTIONS[action]
     end
+    actions
   end
 
   # these resource checks are made at VM start/restore time
@@ -158,11 +170,12 @@ class Vm < ActiveRecord::Base
     return return_val
   end
 
-  def queue_action(user, action)
+  def queue_action(user, action, data = nil)
     return false unless get_action_list.include?(action)
     task = VmTask.new({ :user    => user,
                         :vm_id   => id,
-                         :action  => action,
+                        :action  => action,
+                        :args    => data,
                         :state   => Task::STATE_QUEUED})
     task.save!
     return true
diff --git a/wui/src/app/models/vm_task.rb b/wui/src/app/models/vm_task.rb
index aa12903..3f52478 100644
--- a/wui/src/app/models/vm_task.rb
+++ b/wui/src/app/models/vm_task.rb
@@ -33,59 +33,97 @@ class VmTask < Task
 
   ACTION_UPDATE_STATE_VM = "update_state_vm"
 
+  # for migrate VM action, args provides the optional target host
+  ACTION_MIGRATE_VM  = "migrate_vm"
+
+  PRIV_OBJECT_VM_POOL = "vm_resource_pool"
+  PRIV_OBJECT_HW_POOL = "get_hardware_pool"
+
+
   # a hash of task actions which point to a hash which define valid state transitions
   ACTIONS = { ACTION_CREATE_VM   => { :label => "Create",
                                       :icon  => "icon_start.png",
                                       :start => Vm::STATE_PENDING,
                                       :running => Vm::STATE_CREATING,
                                       :success => Vm::STATE_STOPPED,
-                                      :failure => Vm::STATE_CREATE_FAILED},
+                                      :failure => Vm::STATE_CREATE_FAILED,
+                                      :privilege => [Permission::PRIV_MODIFY,
+                                                     PRIV_OBJECT_VM_POOL]},
               ACTION_START_VM    => { :label => "Start",
                                       :icon  => "icon_start.png",
                                       :start => Vm::STATE_STOPPED,
                                       :running => Vm::STATE_STARTING,
                                       :success => Vm::STATE_RUNNING,
-                                      :failure => Vm::STATE_STOPPED}, 
+                                      :failure => Vm::STATE_STOPPED,
+                                      :privilege => [Permission::PRIV_VM_CONTROL,
+                                                     PRIV_OBJECT_VM_POOL]},
               ACTION_SHUTDOWN_VM => { :label => "Shutdown",
                                       :icon  => "icon_x.png",
                                       :start => Vm::STATE_RUNNING,
                                       :running => Vm::STATE_STOPPING,
                                       :success => Vm::STATE_STOPPED,
-                                      :failure => Vm::STATE_RUNNING}, 
+                                      :failure => Vm::STATE_RUNNING,
+                                      :privilege => [Permission::PRIV_VM_CONTROL,
+                                                     PRIV_OBJECT_VM_POOL]},
               ACTION_SUSPEND_VM  => { :label => "Suspend",
                                       :icon  => "icon_suspend.png",
                                       :start => Vm::STATE_RUNNING,
                                       :running => Vm::STATE_SUSPENDING,
                                       :success => Vm::STATE_SUSPENDED,
-                                      :failure => Vm::STATE_RUNNING}, 
+                                      :failure => Vm::STATE_RUNNING,
+                                      :privilege => [Permission::PRIV_VM_CONTROL,
+                                                     PRIV_OBJECT_VM_POOL]},
               ACTION_RESUME_VM   => { :label => "Resume",
                                       :icon  => "icon_start.png",
                                       :start => Vm::STATE_SUSPENDED,
                                       :running => Vm::STATE_RESUMING,
                                       :success => Vm::STATE_RUNNING,
-                                      :failure => Vm::STATE_SUSPENDED},
+                                      :failure => Vm::STATE_SUSPENDED,
+                                      :privilege => [Permission::PRIV_VM_CONTROL,
+                                                     PRIV_OBJECT_VM_POOL]},
               ACTION_SAVE_VM     => { :label => "Save",
                                       :icon  => "icon_save.png",
                                       :start => Vm::STATE_RUNNING,
                                       :running => Vm::STATE_SAVING,
                                       :success => Vm::STATE_SAVED,
-                                      :failure => Vm::STATE_RUNNING},
+                                      :failure => Vm::STATE_RUNNING,
+                                      :privilege => [Permission::PRIV_VM_CONTROL,
+                                                     PRIV_OBJECT_VM_POOL]},
               ACTION_RESTORE_VM  => { :label => "Restore",
                                       :icon  => "icon_restore.png",
                                       :start => Vm::STATE_SAVED,
                                       :running => Vm::STATE_RESTORING,
                                       :success => Vm::STATE_RUNNING,
-                                      :failure => Vm::STATE_SAVED} }
+                                      :failure => Vm::STATE_SAVED,
+                                      :privilege => [Permission::PRIV_VM_CONTROL,
+                                                     PRIV_OBJECT_VM_POOL]},
+              ACTION_MIGRATE_VM  => { :label => "Migrate",
+                                      :icon  => "icon_restore.png",
+                                      :start => Vm::STATE_RUNNING,
+                                      :running => Vm::STATE_MIGRATING,
+                                      :success => Vm::STATE_RUNNING,
+                                      :failure => Vm::STATE_RUNNING,
+                                      :privilege => [Permission::PRIV_MODIFY,
+                                                     PRIV_OBJECT_HW_POOL],
+                                      :popup_action => 'migrate'} }
 
-  VALID_ACTIONS_PER_VM_STATE = {  Vm::STATE_PENDING       => [ACTION_CREATE_VM],
-                                  Vm::STATE_RUNNING       => [ACTION_SHUTDOWN_VM,
-                                                              ACTION_SUSPEND_VM,
-                                                              ACTION_SAVE_VM],
-                                  Vm::STATE_STOPPED       => [ACTION_START_VM],
-                                  Vm::STATE_SUSPENDED     => [ACTION_RESUME_VM],
-                                  Vm::STATE_SAVED         => [ACTION_RESTORE_VM],
-                                  Vm::STATE_CREATE_FAILED => [],
-                                  Vm::STATE_INVALID       => []}
+  def self.valid_actions_for_vm_state(state, vm=nil, user=nil)
+    actions = []
+    ACTIONS.each do |action, hash|
+      if hash[:start] == state
+        add_action = true
+        print "vm: #{vm}\n user: #{user}\n"
+        if (vm and user)
+          pool = vm.send(hash[:privilege][1])
+          print "pool: #{pool}\n privilege: #{hash[:privilege][1]}\n"
+          add_action = pool ? pool.has_privilege(user, hash[:privilege][0]) : false
+        end
+        print "add_action: #{add_action}\n"
+        actions << action if add_action
+      end
+    end
+    actions
+  end
 
   def self.action_label(action)
     return ACTIONS[action][:label]
diff --git a/wui/src/app/views/hardware/show_hosts.rhtml b/wui/src/app/views/hardware/show_hosts.rhtml
index aaf28b6..167c601 100644
--- a/wui/src/app/views/hardware/show_hosts.rhtml
+++ b/wui/src/app/views/hardware/show_hosts.rhtml
@@ -60,7 +60,10 @@
    <div class="data_section">
       <%= render :partial => "/host/grid", :locals => { :table_id => "hosts_grid",
                                                         :hwpool => @pool,
-                                                        :exclude_id => nil,
+                                                        :exclude_pool => nil,
+                                                        :exclude_host => nil,
+                                                        :show_pool => false,
+                                                        :checkboxes => true,
                                                         :on_select => "hosts_select", 
                                                         :on_deselect => "load_widget_deselect",
                                                         :on_hover => "load_widget_hover",
diff --git a/wui/src/app/views/hardware/show_storage.rhtml b/wui/src/app/views/hardware/show_storage.rhtml
index ec1a82d..dc1460a 100644
--- a/wui/src/app/views/hardware/show_storage.rhtml
+++ b/wui/src/app/views/hardware/show_storage.rhtml
@@ -66,7 +66,7 @@
   <div class="data_section">
        <%= render :partial => "/storage/grid", :locals => { :table_id => "storage_grid",
                                                             :hwpool => @pool,
-                                                            :exclude_id => nil,
+                                                            :exclude_pool => nil,
                                                             :on_select => "storage_select" } %>
   </div>
 
diff --git a/wui/src/app/views/host/_grid.rhtml b/wui/src/app/views/host/_grid.rhtml
index 98a8af4..d4d4d11 100644
--- a/wui/src/app/views/host/_grid.rhtml
+++ b/wui/src/app/views/host/_grid.rhtml
@@ -2,20 +2,25 @@
 
 <% hosts_per_page = 40 %>
 <div id="<%= table_id %>_div">
-<form id="<%= table_id %>_form">
+<%= '<form id="#{table_id}_form">' if checkboxes %>
 <table id="<%= table_id %>" style="display:none"></table>
-</form>
+<%= '</form>' if checkboxes %>
 </div>
 <script type="text/javascript">
     $("#<%= table_id %>").flexigrid
     (
     {
-    url: '<%=  url_for :controller => "hardware", :action => "hosts_json", :id => (hwpool.nil? ? nil : hwpool.id), :exclude_id => exclude_id %>',
+    url: '<%=  url_for :controller => "hardware",
+                       :action => "hosts_json",
+                       :id => (hwpool.nil? ? nil : hwpool.id),
+                       :exclude_pool => exclude_pool,
+                       :exclude_host => exclude_host,
+                       :checkboxes => checkboxes %>',
     dataType: 'json',
     colModel : [
-        {display: '', width : 20, align: 'left', process: <%= table_id %>checkbox},
+        <%= "{display: '', width : 20, align: 'left', process: #{table_id}checkbox}," if checkboxes %>
         {display: 'Hostname', name : 'hostname', width : 60, align: 'left'},
-        <%= "{display: 'Hardware Pool', name : 'pools.name', width : 100, align: 'left'}," if exclude_id %>
+        <%= "{display: 'Hardware Pool', name : 'pools.name', width : 100, align: 'left'}," if exclude_pool %>
         {display: 'UUID', name : 'uuid', width : 180, align: 'left'},
         {display: 'Hypervisor', name : 'hypervisor_type', width : 60, align: 'left'},
         {display: 'CPUs', name : 'num_cpus', width : 30, align: 'left'},
diff --git a/wui/src/app/views/host/addhost.html.erb b/wui/src/app/views/host/addhost.html.erb
index cfcc43b..41b6213 100644
--- a/wui/src/app/views/host/addhost.html.erb
+++ b/wui/src/app/views/host/addhost.html.erb
@@ -8,7 +8,10 @@
 <div class="panel_header"></div>
 <div class="dialog_body">
   <%= render :partial => "/host/grid", :locals => { :table_id => "addhosts_grid",
-             :hwpool => nil, :exclude_id => @hardware_pool.id,
+             :hwpool => nil,
+             :exclude_pool => @hardware_pool.id,
+             :exclude_host => nil,
+             :checkboxes => true,
              :on_select => "load_widget_select",
              :on_deselect => "load_widget_deselect",
              :on_hover => "load_widget_hover",
diff --git a/wui/src/app/views/host/quick_summary.rhtml b/wui/src/app/views/host/quick_summary.rhtml
new file mode 100644
index 0000000..eceb561
--- /dev/null
+++ b/wui/src/app/views/host/quick_summary.rhtml
@@ -0,0 +1 @@
+  <%=h @host.hostname %>
diff --git a/wui/src/app/views/storage/_grid.rhtml b/wui/src/app/views/storage/_grid.rhtml
index 8b10aaa..3bdf407 100644
--- a/wui/src/app/views/storage/_grid.rhtml
+++ b/wui/src/app/views/storage/_grid.rhtml
@@ -9,12 +9,12 @@
     $("#<%= table_id %>").flexigrid
     (
     {
-    url: '<%=  url_for :controller => "hardware", :action => "storage_pools_json", :id => (hwpool.nil? ? nil : hwpool.id), :exclude_id => exclude_id %>',
+    url: '<%=  url_for :controller => "hardware", :action => "storage_pools_json", :id => (hwpool.nil? ? nil : hwpool.id), :exclude_pool => exclude_pool %>',
     dataType: 'json',
     colModel : [
         {display: '', width : 20, align: 'left', process: <%= table_id %>checkbox},
         {display: 'Alias', width : 180, align: 'left'},
-        <%= "{display: 'Hardware Pool', name : 'pools.name', width : 100, align: 'left'}," if exclude_id %>
+        <%= "{display: 'Hardware Pool', name : 'pools.name', width : 100, align: 'left'}," if exclude_pool %>
         {display: 'IP', name : 'ip_addr', width : 80, align: 'left'},
         {display: 'Type', name : 'storage_pools.type', width : 80, align: 'left'}
         ],
diff --git a/wui/src/app/views/storage/add.rhtml b/wui/src/app/views/storage/add.rhtml
index 5dd70e6..11cda06 100644
--- a/wui/src/app/views/storage/add.rhtml
+++ b/wui/src/app/views/storage/add.rhtml
@@ -3,7 +3,7 @@
 <div class="dialog_body_small">
 <div class="panel_header"></div>
   <%= render :partial => "/storage/grid", :locals => { :table_id => "addstorage_grid",
-             :hwpool => nil, :exclude_id => @hardware_pool.id,
+             :hwpool => nil, :exclude_pool => @hardware_pool.id,
              :on_select => "false" } %>
 </div>
 <%= popup_footer("add_storage('#{url_for :controller => 'hardware', 
diff --git a/wui/src/app/views/vm/migrate.rhtml b/wui/src/app/views/vm/migrate.rhtml
new file mode 100644
index 0000000..f94723a
--- /dev/null
+++ b/wui/src/app/views/vm/migrate.rhtml
@@ -0,0 +1,81 @@
+<%- content_for :title do -%>
+  Migrate Virtual Machine
+<%- end -%>
+<%- content_for :description do -%>
+  Please choose migration destination. Leave the selection blank to allow oVirt to choose the most appropriate destination host.
+<%- end -%>
+<script type="text/javascript">
+<%= popup_footer("migrate_vm()", "Migrate") %>
+  function migrate_vm_select(selected_rows)
+  {
+    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)
+    {
+      $('#selected_migration_target').load('<%= url_for :controller => "host", :action => "quick_summary" %>',
+                { id: parseInt(selected_ids[0].substring(3))});
+      $('#vm_action_data').val(selected_ids[0].substring(3));
+    }
+  }
+  function migrate_vm_deselect(selected_rows)
+  {
+    var selected_ids = new Array()
+    for(i=0; i<selected_rows.length; i++) {
+      load_widget_deselect(selected_rows[i]);
+      selected_ids[i] = selected_rows[i].id;
+    }
+    refresh_summary_static('selected_migration_target', '<div class="selection_left"> \
+    <div>No migration target selected.</div> \
+    </div>')
+    $('#vm_action_data').val('')
+  }
+</script>
+<div class="panel_header"></div>
+
+
+<form method="POST" id="migrate_vm_form" action="<%= url_for :action => 'vm_action' %>" >
+<div class="dialog_form">
+    <%= error_messages_for 'migrate_vm' %>
+
+  <%= render :partial => "/host/grid", :locals => { :table_id => "migrate_vm_grid",
+             :hwpool => @vm.get_hardware_pool,
+             :exclude_pool => nil,
+             :exclude_host => @vm.host_id,
+             :checkboxes => false,
+             :on_select => "migrate_vm_select",
+             :on_deselect => "migrate_vm_deselect",
+             :on_hover => "load_widget_hover",
+             :on_unhover => "load_widget_unhover"  } %>
+
+  <% form_tag  do %>
+    <!--[form:migrate_vm]-->
+    <%= hidden_field_tag 'id', @vm.id %>
+    <%= hidden_field_tag 'vm_action', VmTask::ACTION_MIGRATE_VM %>
+    Selected Migration Target:
+    <div id='selected_migration_target'>
+      <div class="selection_left">
+        <div>No migration target selected.</div>
+      </div>
+    </div>
+    <%= hidden_field_tag 'vm_action_data', "" %>
+  <% end %>
+</div>
+<%= popup_footer("$('#migrate_vm_form').submit()", "Migrate Virtual Machine") %>
+</form>
+<script type="text/javascript">
+$(function() {
+    var vmoptions = {
+        target:        '<%= url_for :action => 'create' %>',   // target element to update
+        //beforeSubmit:  showStorageRequest,  // pre-submit callback
+	dataType:      'json',
+        success:       afterVm  // post-submit callback
+    };
+
+    // bind form using 'ajaxForm'
+    $('#migrate_vm_form').ajaxForm(vmoptions);
+});
+</script>
+
diff --git a/wui/src/app/views/vm/show.rhtml b/wui/src/app/views/vm/show.rhtml
index 8b0a760..fe671ef 100644
--- a/wui/src/app/views/vm/show.rhtml
+++ b/wui/src/app/views/vm/show.rhtml
@@ -17,10 +17,17 @@
     <%= link_to image_tag("icon_edit.png") + " Edit",
                           {:controller => 'vm', :action => 'edit', :id => @vm},
                           :rel=>"facebox[.bolder]", :class=>"selection_facebox" %>
-    <% for action in @actions %>
-      <a href="#" onClick="single_vm_action('<%= action[1] %>')">
-        <%= image_tag action[2] %> <%= action[0] %>
-      </a> 
+    <% for name, action in @actions %>
+      <% if action[:popup_action] -%>
+        <%= link_to image_tag(action[:icon]) + action[:label],
+                          {:controller => 'vm',
+                           :action => action[:popup_action], :id => @vm},
+                          :rel=>"facebox[.bolder]", :class=>"selection_facebox" %>
+      <% else -%>
+        <a href="#" onClick="single_vm_action('<%= name %>')">
+          <%= image_tag action[:icon] %> <%= action[:label] %>
+        </a>
+      <% end -%>
     <% end %>
     <a href="#" onClick="cancel_queued_tasks()">
       <%= image_tag "icon_x.png" %> Cancel queued tasks
diff --git a/wui/src/public/javascripts/flexigrid.js b/wui/src/public/javascripts/flexigrid.js
index d7b6416..3715e6f 100644
--- a/wui/src/public/javascripts/flexigrid.js
+++ b/wui/src/public/javascripts/flexigrid.js
@@ -719,7 +719,9 @@
 									    } 
                                         $(this).toggleClass('trSelected');
                                         if($(this).hasClass('trSelected')){
-									        if (p.onSelect) p.onSelect($(t).find("tr.trSelected"));
+                                            if (p.onSelect) p.onSelect($(t).find("tr.trSelected"));
+                                        } else {
+                                            if (p.onDeselect) p.onDeselect(this);
                                         }
 									}
 							)
diff --git a/wui/src/public/javascripts/ovirt.js b/wui/src/public/javascripts/ovirt.js
index c776458..e0aa222 100644
--- a/wui/src/public/javascripts/ovirt.js
+++ b/wui/src/public/javascripts/ovirt.js
@@ -74,7 +74,7 @@ function ajax_validation(response, status)
   if (response.object) {
     $(".fieldWithErrors").removeClass("fieldWithErrors");
     $("div.errorExplanation").remove();
-    if (!response.success) {
+    if (!response.success && response.errors ) {
       for(i=0; i<response.errors.length; i++) { 
         var element = $("div.form_field:has(#"+response.object + "_" + response.errors[i][0]+")");
         if (element) {
-- 
1.5.5.1




More information about the ovirt-devel mailing list