Gilad Chaplik has uploaded a new change for review.

Change subject: frontend: NUMA support
......................................................................

frontend: NUMA support

For more information see: http://www.ovirt.org/Features/NUMA_and_Virtual_NUMA

Change-Id: I0712ea82b87d4fe9fc25f196183136485c0c4381
Bug-Url: https://bugzilla.redhat.com/1134880
Signed-off-by: Gilad Chaplik <gchap...@redhat.com>
---
M frontend/webadmin/modules/gwt-common/exclude-filters.xml
M 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/CommonApplicationConstants.java
M 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/CommonApplicationMessages.java
M 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/CommonApplicationResources.java
M 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/gin/BasePresenterModule.java
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/gin/WidgetModule.java
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/presenter/CollapsiblePanelPresenterWidget.java
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/presenter/popup/numa/NumaSupportPopupPresenterWidget.java
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/presenter/popup/numa/NumaVmSelected.java
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/presenter/popup/numa/UnassignedVNumaNodesPanelPresenterWidget.java
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/presenter/popup/numa/UpdatedVnuma.java
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/CollapsiblePanelView.java
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/CollapsiblePanelView.ui.xml
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/AssignedVNumaNodesPanel.java
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/AssignedVNumaNodesPanel.ui.xml
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/CpuSummaryPanel.java
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/CpuSummaryPanel.ui.xml
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/DragTargetScrollPanel.java
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/DragTargetScrollPanel.ui.xml
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/DraggableVirtualNumaPanel.java
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/DraggableVirtualNumaPanel.ui.xml
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/HostSummaryContentPanel.java
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/HostSummaryContentPanel.ui.xml
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/MemorySummaryPanel.java
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/MemorySummaryPanel.ui.xml
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/NumaPanel.java
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/NumaPanel.ui.xml
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/NumaSupportPopupView.java
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/NumaSupportPopupView.ui.xml
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/NumaTitleTemplate.java
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/SocketPanel.java
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/SocketPanel.ui.xml
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/UnassignedVNumaNodesPanelView.java
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/UnassignedVNumaNodesPanelView.ui.xml
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/VNumaTitleTemplate.java
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/VirtualNumaPanel.java
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/VirtualNumaPanel.ui.xml
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/VmTitlePanel.java
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/VmTitlePanel.ui.xml
A 
frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/collapsed_header_icon.png
A 
frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/expanded_header_icon.png
A 
frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/drag_handle.png
A 
frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/partial_vnuma_dark_icon.png
A 
frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/partial_vnuma_light_icon.png
A 
frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/pinned_partial_vnuma_dark_icon.png
A 
frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/pinned_partial_vnuma_light_icon.png
A 
frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/pinned_vnuma_dark_icon.png
A 
frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/pinned_vnuma_light_icon.png
A 
frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/vnuma_dark_icon.png
A 
frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/vnuma_icon.png
A 
frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/vnuma_light_icon.png
M 
frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/dataprovider/AsyncDataProvider.java
M 
frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/help/HelpTag.java
M 
frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/hosts/HostListModel.java
A 
frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/hosts/numa/NumaSupportModel.java
A 
frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/hosts/numa/VNodeModel.java
M 
frontend/webadmin/modules/uicompat/src/main/java/org/ovirt/engine/ui/uicompat/UIMessages.java
M 
frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/ApplicationConstants.java
M 
frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/ApplicationMessages.java
M 
frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/ApplicationResources.java
M 
frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/gin/uicommon/HostModule.java
M 
frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/tab/MainTabHostView.java
62 files changed, 2,701 insertions(+), 6 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/93/33193/1

diff --git a/frontend/webadmin/modules/gwt-common/exclude-filters.xml 
b/frontend/webadmin/modules/gwt-common/exclude-filters.xml
index 7e489bf..70331bf 100644
--- a/frontend/webadmin/modules/gwt-common/exclude-filters.xml
+++ b/frontend/webadmin/modules/gwt-common/exclude-filters.xml
@@ -196,4 +196,55 @@
      <Match>
         <Bug pattern="SIC_INNER_SHOULD_BE_STATIC" />
      </Match>
+
+       <!--
+        findbugs complain of unused field in class.
+        This is a GWT class and use to generate code
+
+        findbugs reason:
+        UuF: Unused field (UUF_UNUSED_FIELD)
+       -->
+     <Match>
+       <Class 
name="org.ovirt.engine.ui.common.presenter.popup.numa.NumaVmSelected" />
+       <Bug code="UuF"/>
+     </Match>
+
+       <!--
+        findbugs complain of unused field in class.
+        This is a GWT class and use to generate code
+
+        findbugs reason:
+        UuF: Unused field (UUF_UNUSED_FIELD)
+       -->
+     <Match>
+       <Class 
name="org.ovirt.engine.ui.common.presenter.popup.numa.UpdatedVnuma" />
+       <Bug code="UuF"/>
+     </Match>
+
+       <!--
+        findbugs complain of using Integer constructor instead of 
Integer.valueOf
+        This class is GWT generated code
+
+        findbugs reason:
+        Dm: Method invokes inefficient Integer constructor; use 
Integer.valueOf(...) instead (DM_NUMBER_CTOR)
+       -->
+     <Match>
+       <Class 
name="org.ovirt.engine.ui.common.presenter.popup.numa.UpdatedVnumaEvent" />
+       <Method name="hashCode"/>
+       <Bug code="Bx"/>
+     </Match>
+
+       <!--
+        findbugs complain of using Boolean constructor instead of 
Boolean.valueOf
+        This calss is GWT generated code
+
+        findbugs reason:
+        Dm: Method invokes inefficient Boolean constructor; use 
Boolean.valueOf(...) instead (DM_BOOLEAN_CTOR)
+       -->
+     <Match>
+       <Class 
name="org.ovirt.engine.ui.common.presenter.popup.numa.UpdatedVnumaEvent" />
+       <Method name="hashCode"/>
+       <Bug pattern="DM_BOOLEAN_CTOR"/>
+     </Match>
+
 </FindBugsFilter>
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/CommonApplicationConstants.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/CommonApplicationConstants.java
index 21e5899..1fe592f 100644
--- 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/CommonApplicationConstants.java
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/CommonApplicationConstants.java
@@ -1917,4 +1917,20 @@
     @DefaultStringValue("CPU Profile")
     String cpuProfileLabel();
 
+    //Numa
+    @DefaultStringValue("Drag a vNUMA onto a NUMA node to pin the vNUMA to 
that node.")
+    String numaUnassignedInstructions();
+
+    @DefaultStringValue("Unassigned virtual nodes")
+    String unassignedVNumaNodesLabel();
+
+    @DefaultStringValue("Totals:")
+    String numaSummaryTotals();
+
+    @DefaultStringValue("Pin to NUMA node")
+    String pinToNumaNode();
+
+    @DefaultStringValue("Un pin virtual node")
+    String unPinNode();
+
 }
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/CommonApplicationMessages.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/CommonApplicationMessages.java
index bacfa8b..bcf766c 100644
--- 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/CommonApplicationMessages.java
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/CommonApplicationMessages.java
@@ -153,4 +153,27 @@
 
     @DefaultMessage("{0} (Previewing: {1})")
     String snapshotPreviewing(String snapshotDescription, String diskAliases);
+
+    //Numa messages
+    @DefaultMessage("{0}_NUMA{1}")
+    String vNumaName(String name, int index);
+
+    @DefaultMessage("{0} CPUs")
+    String numaTotalCpus(int totalCpu);
+
+    @DefaultMessage("{0}% Used")
+    String numaPercentUsed(int percentage);
+
+    @DefaultMessage("{0} MB")
+    String numaMemory(long totalMemory);
+
+    @DefaultMessage("{0} MB used")
+    String numaMemoryUsed(long totalMemoryUsed);
+
+    @DefaultMessage("Socket {0}")
+    SafeHtml numaSocketNumber(int nodeIndex);
+
+    @DefaultMessage("NUMA {0}")
+    String numaNode(int index);
+
 }
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/CommonApplicationResources.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/CommonApplicationResources.java
index 5caf7da..bc07283 100644
--- 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/CommonApplicationResources.java
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/CommonApplicationResources.java
@@ -280,4 +280,42 @@
 
     @Source("images/separated.png")
     ImageResource separatedIcon();
+
+    //Collapsible panel
+    @Source("images/collapsed_header_icon.png")
+    ImageResource collapsedHeaderArrow();
+
+    @Source("images/expanded_header_icon.png")
+    ImageResource expandedHeaderArrow();
+
+    //Numa popup
+    @Source("images/numa/vnuma_icon.png")
+    ImageResource vNumaTitleIcon();
+
+    @Source("images/numa/partial_vnuma_light_icon.png")
+    ImageResource partialVNumaIcon();
+
+    @Source("images/numa/pinned_partial_vnuma_light_icon.png")
+    ImageResource pinnedPartialVNumaIcon();
+
+    @Source("images/numa/vnuma_light_icon.png")
+    ImageResource vNumaIcon();
+
+    @Source("images/numa/pinned_vnuma_light_icon.png")
+    ImageResource pinnedVNumaIcon();
+
+    @Source("images/numa/drag_handle.png")
+    ImageResource dragHandleIcon();
+
+    @Source("images/numa/pinned_partial_vnuma_dark_icon.png")
+    ImageResource darkPinnedPartialVNumaIcon();
+
+    @Source("images/numa/pinned_vnuma_dark_icon.png")
+    ImageResource darkPinnedVNumaIcon();
+
+    @Source("images/numa/partial_vnuma_dark_icon.png")
+    ImageResource darkPartialVNumaIcon();
+
+    @Source("images/numa/vnuma_dark_icon.png")
+    ImageResource darkVNumaIcon();
 }
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/gin/BasePresenterModule.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/gin/BasePresenterModule.java
index 07629db..616e992 100644
--- 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/gin/BasePresenterModule.java
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/gin/BasePresenterModule.java
@@ -1,17 +1,23 @@
 package org.ovirt.engine.ui.common.gin;
 
+import org.ovirt.engine.ui.common.presenter.CollapsiblePanelPresenterWidget;
 import org.ovirt.engine.ui.common.presenter.ScrollableTabBarPresenterWidget;
 import org.ovirt.engine.ui.common.presenter.popup.ConsolePopupPresenterWidget;
 import 
org.ovirt.engine.ui.common.presenter.popup.DefaultConfirmationPopupPresenterWidget;
 import org.ovirt.engine.ui.common.presenter.popup.ErrorPopupPresenterWidget;
 import 
org.ovirt.engine.ui.common.presenter.popup.RemoveConfirmationPopupPresenterWidget;
 import 
org.ovirt.engine.ui.common.presenter.popup.RolePermissionsRemoveConfirmationPopupPresenterWidget;
+import 
org.ovirt.engine.ui.common.presenter.popup.numa.NumaSupportPopupPresenterWidget;
+import 
org.ovirt.engine.ui.common.presenter.popup.numa.UnassignedVNumaNodesPanelPresenterWidget;
+import org.ovirt.engine.ui.common.view.CollapsiblePanelView;
 import org.ovirt.engine.ui.common.view.ScrollableTabBarView;
 import org.ovirt.engine.ui.common.view.popup.ConsolePopupView;
 import org.ovirt.engine.ui.common.view.popup.DefaultConfirmationPopupView;
 import org.ovirt.engine.ui.common.view.popup.ErrorPopupView;
 import org.ovirt.engine.ui.common.view.popup.RemoveConfirmationPopupView;
 import 
org.ovirt.engine.ui.common.view.popup.RolePermissionsRemoveConfirmationPopupView;
+import org.ovirt.engine.ui.common.view.popup.numa.NumaSupportPopupView;
+import 
org.ovirt.engine.ui.common.view.popup.numa.UnassignedVNumaNodesPanelView;
 
 import com.gwtplatform.mvp.client.gin.AbstractPresenterModule;
 
@@ -46,7 +52,17 @@
         bindPresenterWidget(ScrollableTabBarPresenterWidget.class,
                 ScrollableTabBarPresenterWidget.ViewDef.class,
                 ScrollableTabBarView.class);
+        bindPresenterWidget(CollapsiblePanelPresenterWidget.class,
+                CollapsiblePanelPresenterWidget.ViewDef.class,
+                CollapsiblePanelView.class);
 
+        // Numa popup.
+        bindPresenterWidget(UnassignedVNumaNodesPanelPresenterWidget.class,
+                UnassignedVNumaNodesPanelPresenterWidget.ViewDef.class,
+                UnassignedVNumaNodesPanelView.class);
+        bindPresenterWidget(NumaSupportPopupPresenterWidget.class,
+                NumaSupportPopupPresenterWidget.ViewDef.class,
+                NumaSupportPopupView.class);
     }
 
 }
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/gin/WidgetModule.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/gin/WidgetModule.java
new file mode 100644
index 0000000..086e1a2
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/gin/WidgetModule.java
@@ -0,0 +1,33 @@
+package org.ovirt.engine.ui.common.gin;
+
+import org.ovirt.engine.ui.common.view.popup.numa.AssignedVNumaNodesPanel;
+import org.ovirt.engine.ui.common.view.popup.numa.CpuSummaryPanel;
+import org.ovirt.engine.ui.common.view.popup.numa.DragTargetScrollPanel;
+import org.ovirt.engine.ui.common.view.popup.numa.DraggableVirtualNumaPanel;
+import org.ovirt.engine.ui.common.view.popup.numa.HostSummaryContentPanel;
+import org.ovirt.engine.ui.common.view.popup.numa.MemorySummaryPanel;
+import org.ovirt.engine.ui.common.view.popup.numa.NumaPanel;
+import org.ovirt.engine.ui.common.view.popup.numa.SocketPanel;
+import org.ovirt.engine.ui.common.view.popup.numa.VirtualNumaPanel;
+import org.ovirt.engine.ui.common.view.popup.numa.VmTitlePanel;
+
+import com.google.gwt.inject.client.AbstractGinModule;
+
+public class WidgetModule extends AbstractGinModule {
+
+    @Override
+    protected void configure() {
+        //NUMA popup widgets.
+        bind(CpuSummaryPanel.class);
+        bind(MemorySummaryPanel.class);
+        bind(NumaPanel.class);
+        bind(SocketPanel.class);
+        bind(AssignedVNumaNodesPanel.class);
+        bind(DraggableVirtualNumaPanel.class);
+        bind(DragTargetScrollPanel.class);
+        bind(VmTitlePanel.class);
+        bind(HostSummaryContentPanel.class);
+        bind(VirtualNumaPanel.class);
+    }
+
+}
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/presenter/CollapsiblePanelPresenterWidget.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/presenter/CollapsiblePanelPresenterWidget.java
new file mode 100644
index 0000000..57eb9b6
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/presenter/CollapsiblePanelPresenterWidget.java
@@ -0,0 +1,44 @@
+package org.ovirt.engine.ui.common.presenter;
+
+import com.google.gwt.user.client.ui.IsWidget;
+import com.google.inject.Inject;
+import com.google.web.bindery.event.shared.EventBus;
+import com.gwtplatform.mvp.client.PresenterWidget;
+import com.gwtplatform.mvp.client.View;
+
+public class CollapsiblePanelPresenterWidget extends
+    PresenterWidget<CollapsiblePanelPresenterWidget.ViewDef> {
+
+    public interface ViewDef extends View {
+        /**
+         * Add the content to the panel
+         * @param widget The widget to add.
+         */
+        void addContentWidget(IsWidget widget);
+        /**
+         * Add the header widget, could be a label, or something more complex.
+         * @param widget The widget to add.
+         */
+        void setTitleWidget(IsWidget widget);
+
+        /**
+         * Remove the content from the panel.
+         */
+        void clearContent();
+
+        /**
+         * Collapse the panel;
+         */
+        void collapsePanel();
+    }
+
+    @Inject
+    public CollapsiblePanelPresenterWidget(EventBus eventBus, ViewDef view) {
+        super(eventBus, view);
+    }
+
+    public void collapsePanel() {
+        getView().collapsePanel();
+    }
+
+}
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/presenter/popup/numa/NumaSupportPopupPresenterWidget.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/presenter/popup/numa/NumaSupportPopupPresenterWidget.java
new file mode 100644
index 0000000..0529e5f
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/presenter/popup/numa/NumaSupportPopupPresenterWidget.java
@@ -0,0 +1,141 @@
+package org.ovirt.engine.ui.common.presenter.popup.numa;
+
+import java.util.List;
+import java.util.Set;
+
+import org.ovirt.engine.core.common.businessentities.VDS;
+import org.ovirt.engine.core.common.businessentities.VM;
+import org.ovirt.engine.core.common.businessentities.VdsNumaNode;
+import 
org.ovirt.engine.ui.common.presenter.AbstractModelBoundPopupPresenterWidget;
+import org.ovirt.engine.ui.common.presenter.CollapsiblePanelPresenterWidget;
+import org.ovirt.engine.ui.uicommonweb.models.hosts.numa.NumaSupportModel;
+import org.ovirt.engine.ui.uicommonweb.models.hosts.numa.VNodeModel;
+import org.ovirt.engine.ui.uicompat.Event;
+import org.ovirt.engine.ui.uicompat.EventArgs;
+import org.ovirt.engine.ui.uicompat.IEventListener;
+
+import com.google.gwt.event.shared.EventBus;
+import com.google.gwt.event.shared.GwtEvent.Type;
+import com.google.gwt.user.client.ui.IsWidget;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.gwtplatform.mvp.client.View;
+import com.gwtplatform.mvp.client.annotations.ContentSlot;
+import com.gwtplatform.mvp.client.proxy.RevealContentHandler;
+
+public class NumaSupportPopupPresenterWidget extends 
AbstractModelBoundPopupPresenterWidget<NumaSupportModel, 
NumaSupportPopupPresenterWidget.ViewDef> {
+
+    public interface ViewDef extends 
AbstractModelBoundPopupPresenterWidget.ViewDef<NumaSupportModel> {
+        public void setUnassignedGroupPanel(View view);
+
+        public void setHostSummaryPanel(IsWidget widget);
+
+        public IsWidget getHostSummaryTitle(int totalCpus, int usedCpus, int 
totalMemory, int usedMemory,
+                int totalNumaNodes, int totalVNumaNodes);
+
+        public void addVNumaInfoPanel(Set<VdsNumaNode> numaNodes, int 
nodeIndex, NumaSupportModel supportModel);
+
+        public IsWidget getHostSummaryContent(VDS selectedItem, 
NumaSupportModel supportModel);
+
+        public void displayVmDetails(VNodeModel vNodeModel);
+
+        void clear();
+    }
+
+    @ContentSlot
+    public static final Type<RevealContentHandler<?>> TYPE_SetUnassignedPanel 
= new Type<RevealContentHandler<?>>();
+
+    private final UnassignedVNumaNodesPanelPresenterWidget 
unassignedVNumaNodesPanelPresenterWidget;
+
+    private final Provider<CollapsiblePanelPresenterWidget> 
collapsiblePanelProvider;
+
+    private NumaSupportModel supportModel;
+
+    public static final Object TYPE_revealHostSummary = new Object();
+
+    public static final Object TYPE_revealSocketInfo = new Object();
+
+    @Inject
+    public NumaSupportPopupPresenterWidget(EventBus eventBus, ViewDef view,
+            UnassignedVNumaNodesPanelPresenterWidget 
unassignedVNumaNodesPanelPresenterWidget,
+            Provider<CollapsiblePanelPresenterWidget> 
collapsiblePanelProvider) {
+        super(eventBus, view);
+        this.collapsiblePanelProvider = collapsiblePanelProvider;
+        this.unassignedVNumaNodesPanelPresenterWidget = 
unassignedVNumaNodesPanelPresenterWidget;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void init(final NumaSupportModel model) {
+        super.init(model);
+        supportModel = model;
+        this.unassignedVNumaNodesPanelPresenterWidget.setModel(model);
+        supportModel.getModelReady().addListener(new IEventListener() {
+            @Override
+            public void eventRaised(Event ev, Object sender, EventArgs args) {
+                modelReady();
+            }
+        });
+    }
+
+    @Override
+    protected void onBind() {
+        registerHandler(getEventBus().addHandler(UpdatedVnumaEvent.getType(),
+                new UpdatedVnumaEvent.UpdatedVnumaHandler() {
+
+            @Override
+            public void onUpdatedVnuma(UpdatedVnumaEvent event) {
+                supportModel.pinVNodeToNumaNode(event.getSourceVmGuid(), 
event.isPinned(),
+                        event.getSourceVNumaNodeIndex(), 
event.getTargetNumaNodeIndex());
+            }
+        }));
+
+        registerHandler(getEventBus().addHandler(NumaVmSelectedEvent.getType(),
+                new NumaVmSelectedEvent.NumaVmSelectedHandler() {
+
+            @Override
+            public void onNumaVmSelected(NumaVmSelectedEvent event) {
+                getView().displayVmDetails(event.getVNodeModel());
+            }
+        }));
+    }
+
+    @Override
+    protected void onReveal() {
+        super.onReveal();
+        setInSlot(TYPE_SetUnassignedPanel, 
unassignedVNumaNodesPanelPresenterWidget);
+        
getView().setUnassignedGroupPanel(unassignedVNumaNodesPanelPresenterWidget.getView());
+    }
+
+    private void modelReady() {
+        unassignedVNumaNodesPanelPresenterWidget.populateView();
+        getView().clear();
+        populateHostSummary();
+        populateSockets();
+    }
+
+    private void populateSockets() {
+        for (int i = 0; i < 
supportModel.getFirstLevelDistanceSetList().size(); i++) {
+            
getView().addVNumaInfoPanel(supportModel.getFirstLevelDistanceSetList().get(i).getSecond(),
 i, supportModel);
+        }
+    }
+
+    private void populateHostSummary() {
+        CollapsiblePanelPresenterWidget hostSummaryPanel = 
collapsiblePanelProvider.get();
+        setInSlot(TYPE_revealHostSummary, hostSummaryPanel);
+        List<VM> vmsWithVNuma = supportModel.getVmsWithvNumaNodeList();
+        int totalVNuma = 0;
+        for (VM vm: vmsWithVNuma) {
+            totalVNuma += vm.getvNumaNodeList().size();
+        }
+        
hostSummaryPanel.getView().setTitleWidget(getView().getHostSummaryTitle(
+                supportModel.getHosts().getSelectedItem().getCpuCores(),
+                supportModel.getHosts().getSelectedItem().getUsageCpuPercent(),
+                supportModel.getHosts().getSelectedItem().getPhysicalMemMb(),
+                
supportModel.getHosts().getSelectedItem().getMemFree().intValue(),
+                supportModel.getNumaNodeList().size(), totalVNuma));
+        
hostSummaryPanel.getView().addContentWidget(getView().getHostSummaryContent(
+                supportModel.getHosts().getSelectedItem(), supportModel));
+        getView().setHostSummaryPanel(hostSummaryPanel);
+    }
+}
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/presenter/popup/numa/NumaVmSelected.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/presenter/popup/numa/NumaVmSelected.java
new file mode 100644
index 0000000..b9ea1fa
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/presenter/popup/numa/NumaVmSelected.java
@@ -0,0 +1,10 @@
+package org.ovirt.engine.ui.common.presenter.popup.numa;
+
+import org.ovirt.engine.ui.uicommonweb.models.hosts.numa.VNodeModel;
+
+import com.gwtplatform.dispatch.annotation.GenEvent;
+
+@GenEvent
+public class NumaVmSelected {
+    VNodeModel vNodeModel;
+}
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/presenter/popup/numa/UnassignedVNumaNodesPanelPresenterWidget.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/presenter/popup/numa/UnassignedVNumaNodesPanelPresenterWidget.java
new file mode 100644
index 0000000..0f21884
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/presenter/popup/numa/UnassignedVNumaNodesPanelPresenterWidget.java
@@ -0,0 +1,80 @@
+package org.ovirt.engine.ui.common.presenter.popup.numa;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.ovirt.engine.core.common.businessentities.VM;
+import org.ovirt.engine.core.common.businessentities.VdsNumaNode;
+import org.ovirt.engine.ui.common.presenter.CollapsiblePanelPresenterWidget;
+import org.ovirt.engine.ui.uicommonweb.models.hosts.numa.NumaSupportModel;
+import org.ovirt.engine.ui.uicommonweb.models.hosts.numa.VNodeModel;
+
+import com.google.gwt.user.client.ui.IsWidget;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.web.bindery.event.shared.EventBus;
+import com.gwtplatform.mvp.client.PresenterWidget;
+import com.gwtplatform.mvp.client.View;
+
+public class UnassignedVNumaNodesPanelPresenterWidget extends
+    PresenterWidget<UnassignedVNumaNodesPanelPresenterWidget.ViewDef> {
+
+    public interface ViewDef extends View {
+        public void addToUnassignedPanel(View view);
+
+        public IsWidget getNodePanelTitle(VM vm, List<VNodeModel> list);
+
+        public IsWidget getNodePanelContent(VM vm, List<VNodeModel> list, 
List<VdsNumaNode> numaNodeList);
+
+        public void addEmptyUnassignPanel();
+
+        void clear();
+    }
+
+    public static final Object TYPE_RevealUnassignedPanels = new Object();
+
+    private final Provider<CollapsiblePanelPresenterWidget> 
collapisblePanelProvider;
+
+    private NumaSupportModel model;
+
+    @Inject
+    public UnassignedVNumaNodesPanelPresenterWidget(EventBus eventBus, ViewDef 
view,
+            Provider<CollapsiblePanelPresenterWidget> 
collapsiblePanelProvider) {
+        super(eventBus, view);
+        this.collapisblePanelProvider = collapsiblePanelProvider;
+    }
+
+    public void setModel(NumaSupportModel model) {
+        this.model = model;
+    }
+
+    public void populateView() {
+        getView().clear();
+        List<VNodeModel> unassignedNodeList = 
model.getUnassignedVNodeModelList();
+        Map<VM, List<VNodeModel>> vmToNodeMap = new HashMap<VM, 
List<VNodeModel>>();
+        for(VM currentVM: this.model.getVmsWithvNumaNodeList()) {
+            List<VNodeModel> nodeModelList = new ArrayList<VNodeModel>();
+            vmToNodeMap.put(currentVM, nodeModelList);
+        }
+        for (VNodeModel vNodeModel: unassignedNodeList) {
+            VM currentVM = vNodeModel.getVm();
+            List<VNodeModel> nodeModels = vmToNodeMap.get(currentVM);
+            nodeModels.add(vNodeModel);
+        }
+        for(Map.Entry<VM, List<VNodeModel>> entry: vmToNodeMap.entrySet()) {
+            CollapsiblePanelPresenterWidget nodePanelPresenter = 
collapisblePanelProvider.get();
+            addToSlot(TYPE_RevealUnassignedPanels, nodePanelPresenter);
+            
nodePanelPresenter.getView().setTitleWidget(getView().getNodePanelTitle(entry.getKey(),
 entry.getValue()));
+            
nodePanelPresenter.getView().addContentWidget(getView().getNodePanelContent(entry.getKey(),
+                    entry.getValue(), model.getNumaNodeList()));
+            if (entry.getValue().isEmpty()) {
+                nodePanelPresenter.collapsePanel();
+            }
+            getView().addToUnassignedPanel(nodePanelPresenter.getView());
+        }
+        getView().addEmptyUnassignPanel();
+    }
+
+}
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/presenter/popup/numa/UpdatedVnuma.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/presenter/popup/numa/UpdatedVnuma.java
new file mode 100644
index 0000000..27b3fa8
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/presenter/popup/numa/UpdatedVnuma.java
@@ -0,0 +1,28 @@
+package org.ovirt.engine.ui.common.presenter.popup.numa;
+
+import org.ovirt.engine.core.compat.Guid;
+
+import com.gwtplatform.dispatch.annotation.GenEvent;
+
+@GenEvent
+public class UpdatedVnuma {
+    /**
+     * The {@cod Guid} of the VM that contains the virtual NUMA node.
+     */
+    Guid sourceVmGuid;
+
+    /**
+     * Is the VM pinned.
+     */
+    boolean pinned;
+
+    /**
+     * The index of the virtual NUMA node on the VM.
+     */
+    int sourceVNumaNodeIndex;
+
+    /**
+     * The target physical NUMA node, -1 means unassigned.
+     */
+    int targetNumaNodeIndex;
+}
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/CollapsiblePanelView.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/CollapsiblePanelView.java
new file mode 100644
index 0000000..95814e5
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/CollapsiblePanelView.java
@@ -0,0 +1,68 @@
+package org.ovirt.engine.ui.common.view;
+
+import org.ovirt.engine.ui.common.presenter.CollapsiblePanelPresenterWidget;
+
+import com.google.gwt.core.shared.GWT;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.uibinder.client.UiHandler;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.IsWidget;
+import com.google.gwt.user.client.ui.ToggleButton;
+import com.google.gwt.user.client.ui.Widget;
+
+public class CollapsiblePanelView extends AbstractView implements 
CollapsiblePanelPresenterWidget.ViewDef {
+
+    public interface ViewUiBinder extends UiBinder<Widget, 
CollapsiblePanelView> {
+        ViewUiBinder uiBinder = GWT.create(ViewUiBinder.class);
+    }
+
+    private static final String INDEX = "index"; //$NON-NLS-1$
+
+    @UiField
+    FlowPanel headerPanel;
+
+    @UiField
+    ToggleButton collapseButton;
+
+    @UiField
+    FlowPanel contentPanel;
+
+    int dragIndex;
+
+    /**
+     * Constructor.
+     */
+    public CollapsiblePanelView() {
+        initWidget(ViewUiBinder.uiBinder.createAndBindUi(this));
+    }
+
+    @Override
+    public void addContentWidget(IsWidget widget) {
+        contentPanel.add(widget);
+    }
+
+    @Override
+    public void clearContent() {
+        contentPanel.clear();
+    }
+
+    @Override
+    public void setTitleWidget(IsWidget widget) {
+        headerPanel.insert(widget, headerPanel.getWidgetCount() - 1);
+    }
+
+    @UiHandler("collapseButton")
+    void handleCollapseClick(ClickEvent event) {
+        contentPanel.setVisible(!contentPanel.isVisible());
+    }
+
+    @Override
+    public void collapsePanel() {
+        if (contentPanel.isVisible()) {
+            collapseButton.setValue(true);
+            contentPanel.setVisible(false);
+        }
+    }
+}
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/CollapsiblePanelView.ui.xml
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/CollapsiblePanelView.ui.xml
new file mode 100644
index 0000000..67c62bb
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/CollapsiblePanelView.ui.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent";>
+<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
+    xmlns:g="urn:import:com.google.gwt.user.client.ui"
+    xmlns:d="urn:import:org.ovirt.engine.ui.common.widget.dialog"
+    xmlns:ge="urn:import:org.ovirt.engine.ui.common.widget.editor.generic"
+    xmlns:e="urn:import:org.ovirt.engine.ui.common.widget.editor">
+
+    <ui:with field='resources' 
type='org.ovirt.engine.ui.common.CommonApplicationResources' />
+
+    <ui:style>
+        .headerPanel {
+            background-color: #EDEDED;
+            color: #75797D;
+        }
+
+        .collapseButton {
+            width: 24px;
+            background: transparent;
+            float:left;
+            border: none;
+            padding: 0px 2px 2px 6px;
+        }
+
+        .endFloat {
+            clear: both;
+        }
+    </ui:style>
+
+    <g:FlowPanel>
+        <g:FlowPanel ui:field="headerPanel" 
addStyleNames="{style.headerPanel}">
+            <g:ToggleButton ui:field="collapseButton" 
addStyleNames="{style.collapseButton}" >
+                <g:upFace image="{resources.expandedHeaderArrow}" />
+                <g:downFace image="{resources.collapsedHeaderArrow}"/>
+            </g:ToggleButton>
+            <g:SimplePanel addStyleNames="{style.endFloat}" />
+        </g:FlowPanel>
+        <g:FlowPanel ui:field="contentPanel" />
+    </g:FlowPanel>
+</ui:UiBinder>
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/AssignedVNumaNodesPanel.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/AssignedVNumaNodesPanel.java
new file mode 100644
index 0000000..f7421d1
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/AssignedVNumaNodesPanel.java
@@ -0,0 +1,81 @@
+package org.ovirt.engine.ui.common.view.popup.numa;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.ovirt.engine.core.common.businessentities.VdsNumaNode;
+import org.ovirt.engine.ui.common.CommonApplicationResources;
+import org.ovirt.engine.ui.common.view.CollapsiblePanelView;
+import org.ovirt.engine.ui.uicommonweb.models.hosts.numa.VNodeModel;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.resources.client.CssResource;
+import 
com.google.gwt.safehtml.shared.OnlyToBeUsedInGeneratedCodeStringBlessedAsSafeHtml;
+import com.google.gwt.safehtml.shared.SafeHtml;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.user.client.ui.AbstractImagePrototype;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+public class AssignedVNumaNodesPanel extends Composite {
+
+    interface WidgetUiBinder extends UiBinder<Widget, AssignedVNumaNodesPanel> 
{
+        WidgetUiBinder uiBinder = GWT.create(WidgetUiBinder.class);
+    }
+
+    interface Style extends CssResource {
+        String numaTitle();
+    }
+
+    private final VNumaTitleTemplate titleTemplate;
+
+    @UiField
+    FlowPanel container;
+
+    @UiField
+    Style style;
+
+    private final Provider<DraggableVirtualNumaPanel> virtualNumaPanelProvider;
+
+    private final CollapsiblePanelView collapsiblePanel;
+
+    private final DragTargetScrollPanel scrollPanel;
+
+    private final CommonApplicationResources resources;
+
+    @Inject
+    public AssignedVNumaNodesPanel(CollapsiblePanelView collapsiblePanel,
+            Provider<DraggableVirtualNumaPanel> virtualNumaPanelProvider, 
DragTargetScrollPanel scrollPanel,
+            CommonApplicationResources resources, VNumaTitleTemplate 
vNumaTitleTemplate) {
+        this.collapsiblePanel = collapsiblePanel;
+        initWidget(WidgetUiBinder.uiBinder.createAndBindUi(this));
+        container.add(collapsiblePanel);
+        this.resources = resources;
+        this.virtualNumaPanelProvider = virtualNumaPanelProvider;
+        this.scrollPanel = scrollPanel;
+        this.titleTemplate = vNumaTitleTemplate;
+        collapsiblePanel.addContentWidget(scrollPanel);
+    }
+
+    public void setNodes(List<VNodeModel> virtualNodes, int numaNodeIndex, 
List<VdsNumaNode> numaNodeList) {
+        String myImageHtml = 
AbstractImagePrototype.create(resources.vNumaTitleIcon()).getHTML();
+        SafeHtml mySafeImageHtml = new 
OnlyToBeUsedInGeneratedCodeStringBlessedAsSafeHtml(myImageHtml);
+        if (virtualNodes == null) {
+            virtualNodes = new ArrayList<VNodeModel>();
+        }
+        SafeHtml title = titleTemplate.title(virtualNodes.size(), 
mySafeImageHtml, style.numaTitle());
+        collapsiblePanel.setTitleWidget(new HTML(title));
+        scrollPanel.setIndex(numaNodeIndex);
+        scrollPanel.clear();
+        for (VNodeModel nodeModel: virtualNodes) {
+            DraggableVirtualNumaPanel numaNodePanel = 
virtualNumaPanelProvider.get();
+            numaNodePanel.setModel(nodeModel, numaNodeList);
+            scrollPanel.add(numaNodePanel);
+        }
+    }
+}
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/AssignedVNumaNodesPanel.ui.xml
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/AssignedVNumaNodesPanel.ui.xml
new file mode 100644
index 0000000..5004e3d
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/AssignedVNumaNodesPanel.ui.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent";>
+<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" 
xmlns:g="urn:import:com.google.gwt.user.client.ui" >
+
+    <ui:style 
type="org.ovirt.engine.ui.common.view.popup.numa.AssignedVNumaNodesPanel.Style">
+        .numaTitle {
+            padding-left: 5px;
+        }
+    </ui:style>
+
+    <g:FlowPanel ui:field="container" />
+</ui:UiBinder>
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/CpuSummaryPanel.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/CpuSummaryPanel.java
new file mode 100644
index 0000000..11c4989
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/CpuSummaryPanel.java
@@ -0,0 +1,51 @@
+package org.ovirt.engine.ui.common.view.popup.numa;
+
+import org.ovirt.engine.ui.common.CommonApplicationMessages;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.inject.Inject;
+
+public class CpuSummaryPanel extends Composite {
+
+    interface WidgetUiBinder extends UiBinder<Widget, CpuSummaryPanel> {
+        WidgetUiBinder uiBinder = GWT.create(WidgetUiBinder.class);
+    }
+
+    private final CommonApplicationMessages messages;
+
+    @UiField
+    Label nameLabel;
+
+    @UiField
+    Label totalLabel;
+
+    @UiField
+    Label percentageLabel;
+
+    @Inject
+    public CpuSummaryPanel(CommonApplicationMessages messages) {
+        initWidget(WidgetUiBinder.uiBinder.createAndBindUi(this));
+        this.messages = messages;
+    }
+
+    public void setName(String name) {
+        nameLabel.setTitle(name);
+        nameLabel.setText(name);
+    }
+
+    public void setCpus(int totalCpus, int usedPercentage) {
+        String totalCpusString = messages.numaTotalCpus(totalCpus);
+
+        totalLabel.setTitle(totalCpusString);
+        totalLabel.setText(totalCpusString);
+
+        String percentageUsed = messages.numaPercentUsed(usedPercentage);
+        percentageLabel.setTitle(percentageUsed);
+        percentageLabel.setText(percentageUsed);
+    }
+}
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/CpuSummaryPanel.ui.xml
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/CpuSummaryPanel.ui.xml
new file mode 100644
index 0000000..f000281
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/CpuSummaryPanel.ui.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent";>
+<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" 
xmlns:g="urn:import:com.google.gwt.user.client.ui">
+
+    <ui:style>
+        .cpuPanel {
+            float: left;
+            padding: 5px;
+        }
+
+        .nameLabelContainer {
+            float: left;
+            padding-right: 5px;
+        }
+
+        .cpuLabelContainer {
+            float: left;
+        }
+
+        .mainText {
+            font-size: medium;
+            color: black;
+        }
+
+        .subText {
+            font-size: smaller;
+            color: #AEAEAE;
+        }
+
+        .clearFloat {
+            clear: both;
+        }
+    </ui:style>
+
+    <g:FlowPanel addStyleNames="{style.cpuPanel}">
+        <g:SimplePanel addStyleNames="{style.nameLabelContainer}">
+            <g:Label ui:field="nameLabel" addStyleNames="{style.mainText}"/>
+        </g:SimplePanel>
+        <g:FlowPanel addStyleNames="{style.cpuLabelContainer}">
+            <g:Label ui:field="totalLabel" addStyleNames="{style.mainText}" />
+            <g:Label ui:field="percentageLabel" 
addStyleNames="{style.subText}" />
+        </g:FlowPanel>
+        <g:SimplePanel addStyleNames="{style.clearFloat}" />
+    </g:FlowPanel>
+
+</ui:UiBinder>
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/DragTargetScrollPanel.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/DragTargetScrollPanel.java
new file mode 100644
index 0000000..1151f66
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/DragTargetScrollPanel.java
@@ -0,0 +1,98 @@
+package org.ovirt.engine.ui.common.view.popup.numa;
+
+import org.ovirt.engine.core.common.utils.Pair;
+import org.ovirt.engine.core.compat.Guid;
+import org.ovirt.engine.ui.common.presenter.popup.numa.UpdatedVnumaEvent;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.event.dom.client.DragLeaveEvent;
+import com.google.gwt.event.dom.client.DragOverEvent;
+import com.google.gwt.event.dom.client.DropEvent;
+import com.google.gwt.event.shared.EventBus;
+import com.google.gwt.event.shared.GwtEvent;
+import com.google.gwt.event.shared.HasHandlers;
+import com.google.gwt.resources.client.CssResource;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.uibinder.client.UiHandler;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.FocusPanel;
+import com.google.gwt.user.client.ui.IsWidget;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.inject.Inject;
+
+public class DragTargetScrollPanel extends Composite implements HasHandlers {
+
+    interface WidgetUiBinder extends UiBinder<Widget, DragTargetScrollPanel> {
+        WidgetUiBinder uiBinder = GWT.create(WidgetUiBinder.class);
+    }
+
+    interface Style extends CssResource {
+        String dragOver();
+    }
+
+    private final EventBus eventBus;
+
+    @UiField
+    FocusPanel container;
+
+    @UiField
+    FlowPanel dragTargetPanel;
+
+    @UiField
+    Style style;
+
+    private int pNumaNodeIndex;
+
+    @Inject
+    public DragTargetScrollPanel(EventBus gwtEventBus) {
+        this.eventBus = gwtEventBus;
+        initWidget(WidgetUiBinder.uiBinder.createAndBindUi(this));
+    }
+
+    public void clear() {
+        dragTargetPanel.clear();
+    }
+
+    public void add(IsWidget widget) {
+        dragTargetPanel.add(widget);
+    }
+
+    @Override
+    public void fireEvent(GwtEvent<?> event) {
+        eventBus.fireEvent(event);
+    }
+
+    @UiHandler("container")
+    void onPanelDragOver(DragOverEvent event) {
+        container.addStyleName(style.dragOver());
+    }
+
+    @UiHandler("container")
+    void onPanelDragLeave(DragLeaveEvent event) {
+        container.removeStyleName(style.dragOver());
+    }
+
+    @UiHandler("container")
+    void onPanelDragDrop(DropEvent event) {
+        Guid vmGuid = Guid.createGuidFromString(event.getData("VM_GID")); 
//$NON-NLS-1$
+        boolean pinned = Boolean.valueOf(event.getData("PINNED")); 
//$NON-NLS-1$
+        int vNumaNodeIndex = Integer.valueOf(event.getData("INDEX")); 
//$NON-NLS-1$
+        container.removeStyleName(style.dragOver());
+        event.preventDefault();
+        UpdatedVnumaEvent.fire(this, vmGuid, pinned, vNumaNodeIndex, 
pNumaNodeIndex);
+    }
+
+    private Pair<Guid, Pair<Boolean, Integer>> parseDropString(String 
dropString) {
+        Pair<Boolean, Integer> pinnedIndexPair = new Pair<Boolean, Integer>();
+        String[] splitString = dropString.split("_"); //$NON-NLS-1$
+        pinnedIndexPair.setFirst(Boolean.valueOf(splitString[1]));
+        pinnedIndexPair.setSecond(Integer.valueOf(splitString[2]));
+        return new Pair<Guid, Pair<Boolean, 
Integer>>(Guid.createGuidFromString(splitString[0]), pinnedIndexPair);
+    }
+
+    public void setIndex(int numaNodeIndex) {
+        this.pNumaNodeIndex = numaNodeIndex;
+    }
+}
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/DragTargetScrollPanel.ui.xml
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/DragTargetScrollPanel.ui.xml
new file mode 100644
index 0000000..74bb005
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/DragTargetScrollPanel.ui.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent";>
+<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" 
xmlns:g="urn:import:com.google.gwt.user.client.ui">
+
+    <ui:style 
type="org.ovirt.engine.ui.common.view.popup.numa.DragTargetScrollPanel.Style">
+        .scrollPanel {
+            overflow-y: scroll;
+            overflow-x: hidden;
+            max-height: 100px;
+            height: 100px;
+            background-color: #EDEDED;
+        }
+
+        .dragOver {
+            border: 1px dotted green;
+        }
+    </ui:style>
+
+    <g:FocusPanel ui:field="container" addStyleNames="{style.scrollPanel}">
+        <g:FlowPanel ui:field="dragTargetPanel" />
+    </g:FocusPanel>
+</ui:UiBinder>
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/DraggableVirtualNumaPanel.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/DraggableVirtualNumaPanel.java
new file mode 100644
index 0000000..a4fc50e
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/DraggableVirtualNumaPanel.java
@@ -0,0 +1,203 @@
+package org.ovirt.engine.ui.common.view.popup.numa;
+
+import java.util.List;
+
+import org.ovirt.engine.core.common.businessentities.VdsNumaNode;
+import org.ovirt.engine.ui.common.CommonApplicationConstants;
+import org.ovirt.engine.ui.common.CommonApplicationMessages;
+import org.ovirt.engine.ui.common.CommonApplicationResources;
+import org.ovirt.engine.ui.common.presenter.popup.numa.NumaVmSelectedEvent;
+import org.ovirt.engine.ui.common.presenter.popup.numa.UpdatedVnumaEvent;
+import org.ovirt.engine.ui.common.widget.MenuBar;
+import org.ovirt.engine.ui.common.widget.PopupPanel;
+import org.ovirt.engine.ui.uicommonweb.models.hosts.numa.VNodeModel;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.event.dom.client.ContextMenuEvent;
+import com.google.gwt.event.dom.client.ContextMenuHandler;
+import com.google.gwt.event.dom.client.DragStartEvent;
+import com.google.gwt.event.dom.client.FocusEvent;
+import com.google.gwt.event.dom.client.MouseOutEvent;
+import com.google.gwt.event.dom.client.MouseOverEvent;
+import com.google.gwt.event.shared.EventBus;
+import com.google.gwt.event.shared.GwtEvent;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.event.shared.HasHandlers;
+import com.google.gwt.resources.client.CssResource;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.uibinder.client.UiHandler;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.FocusPanel;
+import com.google.gwt.user.client.ui.Image;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.inject.Inject;
+
+public class DraggableVirtualNumaPanel extends Composite implements 
HasHandlers {
+
+    interface WidgetUiBinder extends UiBinder<Widget, 
DraggableVirtualNumaPanel> {
+        WidgetUiBinder uiBinder = GWT.create(WidgetUiBinder.class);
+    }
+
+    interface Style extends CssResource {
+        String panelOver();
+    }
+
+    static final PopupPanel menuPopup = new PopupPanel(true);
+
+    @UiField
+    FocusPanel container;
+
+    @UiField(provided=true)
+    VirtualNumaPanel numaPanel;
+
+    @UiField
+    Image dragHandle;
+
+    @UiField
+    Style style;
+
+    private VNodeModel nodeModel;
+
+    private final EventBus eventBus;
+
+    private final CommonApplicationConstants commonConstants;
+    private final CommonApplicationMessages commonMessages;
+
+    private HandlerRegistration contextMenuHandlerRegistration;
+    private MenuBar menuBar;
+
+    @Inject
+    public DraggableVirtualNumaPanel(EventBus gwtEventBus, 
CommonApplicationResources commonResources,
+            CommonApplicationMessages messages, CommonApplicationConstants 
commonConstants,
+            VirtualNumaPanel virtualNumaPanel) {
+        numaPanel = virtualNumaPanel;
+        initWidget(WidgetUiBinder.uiBinder.createAndBindUi(this));
+        initializeResouceIcons(commonResources);
+        this.eventBus = gwtEventBus;
+        this.commonConstants = commonConstants;
+        this.commonMessages = messages;
+        enableDrag(true);
+    }
+
+    @Override
+    public void onLoad() {
+        super.onLoad();
+        contextMenuHandlerRegistration = numaPanel.addDomHandler(new 
ContextMenuHandler() {
+            @Override
+            public void onContextMenu(ContextMenuEvent event) {
+                NativeEvent nativeEvent = event.getNativeEvent();
+                showContextMenu(nativeEvent.getClientX(), 
nativeEvent.getClientY());
+                event.stopPropagation();
+                event.preventDefault();
+            }
+        }, ContextMenuEvent.getType());
+    }
+
+    @Override
+    public void onUnload() {
+        super.onUnload();
+        contextMenuHandlerRegistration.removeHandler();
+    }
+
+    private void initializeResouceIcons(CommonApplicationResources resources) {
+        
numaPanel.setPinnedPartialVNumaIcon(resources.pinnedPartialVNumaIcon());
+        numaPanel.setPinnedVNumaIcon(resources.pinnedVNumaIcon());
+        numaPanel.setPartialVNumaIcon(resources.partialVNumaIcon());
+        numaPanel.setvNumaIcon(resources.vNumaIcon());
+    }
+
+    @UiHandler("container")
+    void handleMouseOver(MouseOverEvent event) {
+        container.addStyleName(style.panelOver());
+        dragHandle.setVisible(true);
+    }
+
+    @UiHandler("container")
+    void handleMouseOut(MouseOutEvent event) {
+        container.removeStyleName(style.panelOver());
+        dragHandle.setVisible(false);
+    }
+
+    @UiHandler("container")
+    void onDragStart(DragStartEvent event) {
+        event.setData("VM_GID", nodeModel.getVm().getId().toString()); 
//$NON-NLS-1$
+        event.setData("PINNED", String.valueOf(nodeModel.isPinned())); 
//$NON-NLS-1$
+        event.setData("INDEX", 
String.valueOf(nodeModel.getVmNumaNode().getIndex())); //$NON-NLS-1$
+        // show a ghost of the widget under cursor.
+        NativeEvent nativeEvent = event.getNativeEvent();
+        int x = nativeEvent.getClientX() - getAbsoluteLeft();
+        int y = nativeEvent.getClientY() - getAbsoluteTop();
+        event.getDataTransfer().setDragImage(getElement(), x, y);
+    }
+
+    @UiHandler("container")
+    void onFocus(FocusEvent event) {
+        NumaVmSelectedEvent.fire(this, this.nodeModel);
+    }
+
+    protected void showContextMenu(int clientX, int clientY) {
+        menuPopup.setWidget(menuBar);
+        menuPopup.setPopupPosition(clientX, clientY);
+        menuPopup.show();
+    }
+
+    /**
+     * Dragging is enabled by default, if you want to alter that behavior, 
call this method with false.
+     * @param enable Enabled or disable dragging of this panel.
+     */
+    public void enableDrag(boolean enable) {
+        if (enable) {
+            getElement().setDraggable(Element.DRAGGABLE_TRUE);
+        } else {
+            getElement().setDraggable(Element.DRAGGABLE_FALSE);
+        }
+    }
+
+    @Override
+    public void setStyleName(String className) {
+        container.setStyleName(className);
+    }
+
+    public void setModel(VNodeModel nodeModel, List<VdsNumaNode> numaNodeList) 
{
+        numaPanel.setModel(nodeModel);
+        this.nodeModel = nodeModel;
+        createMenu(numaNodeList, nodeModel.getVmNumaNode().getIndex());
+    }
+
+    private void createMenu(final List<VdsNumaNode> numaNodeList, int 
indexToSkip) {
+        menuBar = new MenuBar(true);
+        for (final VdsNumaNode numaNode : numaNodeList) {
+            final int nodeIndex = numaNode.getIndex();
+            menuBar.addItem(commonMessages.numaNode(nodeIndex), new Command() {
+
+                @Override
+                public void execute() {
+                    UpdatedVnumaEvent.fire(DraggableVirtualNumaPanel.this, 
nodeModel.getVm().getId(),
+                            nodeModel.isPinned(), 
nodeModel.getVmNumaNode().getIndex(), nodeIndex);
+                    menuPopup.hide();
+                }
+            });
+        }
+        if (nodeModel.isPinned()) {
+            menuBar.addSeparator();
+            menuBar.addItem(commonConstants.unPinNode(), new Command() {
+
+                @Override
+                public void execute() {
+                    UpdatedVnumaEvent.fire(DraggableVirtualNumaPanel.this, 
nodeModel.getVm().getId(),
+                            nodeModel.isPinned(), 
nodeModel.getVmNumaNode().getIndex(), -1);
+                    menuPopup.hide();
+                }
+            });
+        }
+    }
+
+    @Override
+    public void fireEvent(GwtEvent<?> event) {
+        eventBus.fireEvent(event);
+    }
+}
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/DraggableVirtualNumaPanel.ui.xml
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/DraggableVirtualNumaPanel.ui.xml
new file mode 100644
index 0000000..640cf76
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/DraggableVirtualNumaPanel.ui.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent";>
+<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" 
xmlns:g="urn:import:com.google.gwt.user.client.ui"
+    xmlns:onu="urn:import:org.ovirt.engine.ui.common.view.popup.numa">
+
+    <ui:with field="commonResources" 
type="org.ovirt.engine.ui.common.CommonApplicationResources" />
+
+    <ui:style 
type="org.ovirt.engine.ui.common.view.popup.numa.DraggableVirtualNumaPanel.Style">
+        .panel {
+            background-color: #969696;
+            color: white;
+            margin: 1px 15px 1px 15px;
+            width: 213px;
+        }
+
+        .imageStyle {
+            float: left;
+            padding-left: 5px;
+        }
+
+        .panelOver {
+            background-color: #0099d2;
+            cursor: pointer;
+        }
+    </ui:style>
+
+    <g:FocusPanel ui:field="container" addStyleNames="{style.panel}">
+        <onu:VirtualNumaPanel ui:field="numaPanel">
+            <g:Image ui:field="dragHandle" 
resource="{commonResources.dragHandleIcon}" addStyleNames="{style.imageStyle}" 
visible="false"/>
+        </onu:VirtualNumaPanel>
+    </g:FocusPanel>
+
+</ui:UiBinder>
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/HostSummaryContentPanel.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/HostSummaryContentPanel.java
new file mode 100644
index 0000000..02ebb76
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/HostSummaryContentPanel.java
@@ -0,0 +1,59 @@
+package org.ovirt.engine.ui.common.view.popup.numa;
+
+import java.util.List;
+
+import org.ovirt.engine.core.common.businessentities.VdsNumaNode;
+import org.ovirt.engine.ui.common.CommonApplicationMessages;
+import org.ovirt.engine.ui.uicommonweb.models.hosts.numa.VNodeModel;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.FocusPanel;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+public class HostSummaryContentPanel extends Composite {
+
+    interface WidgetUiBinder extends UiBinder<Widget, HostSummaryContentPanel> 
{
+        WidgetUiBinder uiBinder = GWT.create(WidgetUiBinder.class);
+    }
+
+    @UiField
+    FocusPanel numaContainer;
+
+    @UiField
+    FlowPanel numaPanel;
+
+    @UiField
+    FocusPanel vNumaContainer;
+
+    @UiField
+    FlowPanel vNumaPanel;
+
+    @Inject
+    Provider<VirtualNumaPanel> virtualNumaPanelProvider;
+
+    private final CommonApplicationMessages messages;
+
+    @Inject
+    public HostSummaryContentPanel(CommonApplicationMessages messages) {
+        initWidget(WidgetUiBinder.uiBinder.createAndBindUi(this));
+        this.messages = messages;
+    }
+
+    public void setModel(List<VdsNumaNode> numaNodes, List<VNodeModel> 
vNodeModels) {
+        for(VNodeModel vNodeModel: vNodeModels) {
+            VirtualNumaPanel panel = virtualNumaPanelProvider.get();
+            panel.setModel(vNodeModel);
+            vNumaPanel.add(panel);
+        }
+        for(VdsNumaNode numaNode: numaNodes) {
+            numaPanel.add(new HTML(messages.numaNode(numaNode.getIndex())));
+        }
+    }
+}
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/HostSummaryContentPanel.ui.xml
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/HostSummaryContentPanel.ui.xml
new file mode 100644
index 0000000..871816c
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/HostSummaryContentPanel.ui.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent";>
+<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" 
xmlns:g="urn:import:com.google.gwt.user.client.ui"
+    xmlns:onu="urn:import:org.ovirt.engine.ui.common.view.popup.numa">
+
+    <ui:style>
+        .container {
+            background-color: white;
+            border: 1px solid #EDEDED;
+        }
+
+        .fancyBarsContainer {
+            width: 200px;
+            min-height: 1px;
+            float: left;
+        }
+
+        .scrollPanel {
+            overflow-y: scroll;
+            overflow-x: hidden;
+            max-height: 100px;
+            height: 100px;
+            width: 180px;
+            padding: 5px;
+            float: left;
+            border-left: 1px solid #EDEDED;
+            margin-top: 1px;
+        }
+
+        .vNumaScrollPanel {
+            background-color: #EDEDED;
+        }
+
+        .clearFloat {
+            clear: both;
+        }
+    </ui:style>
+
+    <g:FlowPanel addStyleNames="{style.container}">
+        <g:FlowPanel addStyleNames="{style.fancyBarsContainer}" />
+        <g:FocusPanel ui:field="numaContainer" 
addStyleNames="{style.scrollPanel}">
+            <g:FlowPanel ui:field="numaPanel" />
+        </g:FocusPanel>
+        <g:FocusPanel ui:field="vNumaContainer" 
addStyleNames="{style.scrollPanel} {style.vNumaScrollPanel}">
+            <g:FlowPanel ui:field="vNumaPanel" />
+        </g:FocusPanel>
+        <g:SimplePanel addStyleNames="{style.clearFloat}" />
+    </g:FlowPanel>
+
+</ui:UiBinder>
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/MemorySummaryPanel.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/MemorySummaryPanel.java
new file mode 100644
index 0000000..59366a9
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/MemorySummaryPanel.java
@@ -0,0 +1,41 @@
+package org.ovirt.engine.ui.common.view.popup.numa;
+
+import org.ovirt.engine.ui.common.CommonApplicationMessages;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.inject.Inject;
+
+public class MemorySummaryPanel extends Composite {
+    interface WidgetUiBinder extends UiBinder<Widget, MemorySummaryPanel> {
+        WidgetUiBinder uiBinder = GWT.create(WidgetUiBinder.class);
+    }
+
+    private final CommonApplicationMessages messages;
+
+    @UiField
+    Label totalLabel;
+
+    @UiField
+    Label usedLabel;
+
+    @Inject
+    public MemorySummaryPanel(CommonApplicationMessages messages) {
+        initWidget(WidgetUiBinder.uiBinder.createAndBindUi(this));
+        this.messages = messages;
+    }
+
+    public void setMemoryStats(long totalMemory, long usedMemory) {
+        String totalMemoryString = messages.numaMemory(totalMemory);
+        totalLabel.setTitle(totalMemoryString);
+        totalLabel.setText(totalMemoryString);
+
+        String usedMemoryString = messages.numaMemoryUsed(usedMemory);
+        usedLabel.setTitle(usedMemoryString);
+        usedLabel.setText(usedMemoryString);
+    }
+}
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/MemorySummaryPanel.ui.xml
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/MemorySummaryPanel.ui.xml
new file mode 100644
index 0000000..8c647c4
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/MemorySummaryPanel.ui.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent";>
+<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" 
xmlns:g="urn:import:com.google.gwt.user.client.ui">
+
+    <ui:style>
+        .memoryPanel {
+            float: left;
+            padding: 5px;
+        }
+
+        .memoryLabelContainer {
+            float:left;
+        }
+
+        .mainText {
+            font-size: medium;
+            color: black;
+        }
+
+        .subText {
+            font-size: smaller;
+            color: #555;
+        }
+
+        .clearFloat {
+            clear: both;
+        }
+    </ui:style>
+
+    <g:FlowPanel addStyleNames="{style.memoryPanel}">
+        <g:FlowPanel addStyleNames="{style.memoryLabelContainer}">
+            <g:Label ui:field="totalLabel" addStyleNames="{style.mainText}" />
+            <g:Label ui:field="usedLabel" addStyleNames="{style.subText}" />
+        </g:FlowPanel>
+        <g:SimplePanel addStyleNames="{style.clearFloat}" />
+    </g:FlowPanel>
+
+</ui:UiBinder>
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/NumaPanel.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/NumaPanel.java
new file mode 100644
index 0000000..7f9a286
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/NumaPanel.java
@@ -0,0 +1,35 @@
+package org.ovirt.engine.ui.common.view.popup.numa;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.inject.Inject;
+
+public class NumaPanel extends Composite {
+    interface WidgetUiBinder extends UiBinder<Widget, NumaPanel> {
+        WidgetUiBinder uiBinder = GWT.create(WidgetUiBinder.class);
+    }
+
+    @UiField(provided=true)
+    CpuSummaryPanel cpuSummaryPanel;
+
+    @UiField(provided=true)
+    MemorySummaryPanel memorySummaryPanel;
+
+    @Inject
+    public NumaPanel(CpuSummaryPanel cpuSummary, MemorySummaryPanel 
memorySummary) {
+        this.cpuSummaryPanel = cpuSummary;
+        this.memorySummaryPanel = memorySummary;
+        initWidget(WidgetUiBinder.uiBinder.createAndBindUi(this));
+    }
+
+    public CpuSummaryPanel getCpuSummaryPanel() {
+        return this.cpuSummaryPanel;
+    }
+
+    public MemorySummaryPanel getMemorySummaryPanel() {
+        return this.memorySummaryPanel;
+    }
+}
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/NumaPanel.ui.xml
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/NumaPanel.ui.xml
new file mode 100644
index 0000000..1987187
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/NumaPanel.ui.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent";>
+<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" 
xmlns:g="urn:import:com.google.gwt.user.client.ui"
+    xmlns:onu="urn:import:org.ovirt.engine.ui.common.view.popup.numa">
+
+    <ui:style>
+        .numaPanel {
+            background-color: white;
+            color: #eee;
+        }
+
+        .clearFloat {
+            clear: both;
+        }
+    </ui:style>
+
+    <g:FlowPanel addStyleNames="{style.numaPanel}">
+        <onu:CpuSummaryPanel ui:field="cpuSummaryPanel" />
+        <onu:MemorySummaryPanel ui:field="memorySummaryPanel" />
+        <g:SimplePanel addStyleNames="{style.clearFloat}" />
+    </g:FlowPanel>
+
+</ui:UiBinder>
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/NumaSupportPopupView.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/NumaSupportPopupView.java
new file mode 100644
index 0000000..52793b0
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/NumaSupportPopupView.java
@@ -0,0 +1,213 @@
+package org.ovirt.engine.ui.common.view.popup.numa;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import org.ovirt.engine.core.common.businessentities.VDS;
+import org.ovirt.engine.core.common.businessentities.VM;
+import org.ovirt.engine.core.common.businessentities.VdsNumaNode;
+import org.ovirt.engine.core.common.businessentities.VmNumaNode;
+import org.ovirt.engine.core.common.utils.Pair;
+import org.ovirt.engine.core.compat.Guid;
+import org.ovirt.engine.ui.common.CommonApplicationConstants;
+import org.ovirt.engine.ui.common.CommonApplicationMessages;
+import org.ovirt.engine.ui.common.CommonApplicationResources;
+import org.ovirt.engine.ui.common.idhandler.ElementIdHandler;
+import 
org.ovirt.engine.ui.common.presenter.popup.numa.NumaSupportPopupPresenterWidget;
+import org.ovirt.engine.ui.common.system.ClientStorage;
+import org.ovirt.engine.ui.common.view.popup.AbstractModelBoundPopupView;
+import org.ovirt.engine.ui.common.widget.dialog.SimpleDialogPanel;
+import org.ovirt.engine.ui.uicommonweb.models.hosts.numa.NumaSupportModel;
+import org.ovirt.engine.ui.uicommonweb.models.hosts.numa.VNodeModel;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.event.shared.EventBus;
+import com.google.gwt.resources.client.CssResource;
+import 
com.google.gwt.safehtml.shared.OnlyToBeUsedInGeneratedCodeStringBlessedAsSafeHtml;
+import com.google.gwt.safehtml.shared.SafeHtml;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.user.client.ui.AbstractImagePrototype;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.IsWidget;
+import com.google.gwt.user.client.ui.SplitLayoutPanel;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.gwtplatform.mvp.client.View;
+
+public class NumaSupportPopupView extends 
AbstractModelBoundPopupView<NumaSupportModel>
+    implements NumaSupportPopupPresenterWidget.ViewDef {
+
+    interface ViewUiBinder extends UiBinder<SimpleDialogPanel, 
NumaSupportPopupView> {
+
+        ViewUiBinder uiBinder = GWT.create(ViewUiBinder.class);
+    }
+
+    interface ViewIdHandler extends ElementIdHandler<NumaSupportPopupView> {
+
+        ViewIdHandler idHandler = GWT.create(ViewIdHandler.class);
+    }
+
+    interface Style extends CssResource {
+        String hostSummaryNumaTitle();
+    }
+
+    static final String DELIMITER = ", "; //$NON-NLS-1$
+    private static final int SPLITTER_THICKNESS = 1;
+
+    @Inject
+    Provider<CpuSummaryPanel> cpuSummaryPanelProvider;
+
+    @Inject
+    Provider<MemorySummaryPanel> memorySummaryPanelProvider;
+
+    @Inject
+    Provider<SocketPanel> socketPanelProvider;
+
+    @Inject
+    Provider<NumaPanel> numaPanelProvider;
+
+    @Inject
+    Provider<AssignedVNumaNodesPanel> assignedVNumaPanelProvider;
+
+    @Inject
+    Provider<HostSummaryContentPanel> hostSummaryContentProvider;
+
+
+    private final CommonApplicationConstants constants;
+    private final CommonApplicationMessages messages;
+    private final CommonApplicationResources resources;
+
+    @UiField
+    FlowPanel groupPanel;
+
+    @UiField
+    FlowPanel hostSummaryPanel;
+
+    @UiField
+    FlowPanel unassignedvNumaNodesContainer;
+
+    @UiField
+    FlowPanel socketListPanel;
+
+    @UiField(provided = true)
+    SplitLayoutPanel horizontalSplitLayoutPanel;
+
+    @UiField
+    Style style;
+
+    final VNumaTitleTemplate vNumaTitleTemplate;
+    final NumaTitleTemplate numaTitleTemplate;
+
+    @Inject
+    public NumaSupportPopupView(EventBus eventBus, ClientStorage 
clientStorage, VNumaTitleTemplate vNumaTitleTemplate,
+            NumaTitleTemplate numaTitleTemplate, CommonApplicationMessages 
messages,
+            CommonApplicationConstants constants, CommonApplicationResources 
resources) {
+        super(eventBus, resources);
+        this.constants = constants;
+        this.messages = messages;
+        this.resources = resources;
+        this.numaTitleTemplate = numaTitleTemplate;
+        this.vNumaTitleTemplate = vNumaTitleTemplate;
+        horizontalSplitLayoutPanel = new SplitLayoutPanel(SPLITTER_THICKNESS);
+        initWidget(ViewUiBinder.uiBinder.createAndBindUi(this));
+        ViewIdHandler.idHandler.generateAndSetIds(this);
+        
horizontalSplitLayoutPanel.setWidgetToggleDisplayAllowed(unassignedvNumaNodesContainer,
 true);
+    }
+
+    @Override
+    public void edit(NumaSupportModel object) {
+    }
+
+    @Override
+    public NumaSupportModel flush() {
+        return null;
+    }
+
+    @Override
+    public void setUnassignedGroupPanel(View view) {
+        unassignedvNumaNodesContainer.insert(view, 1);
+    }
+
+    @Override
+    public IsWidget getHostSummaryTitle(int totalCpus, int usedCpuPercentage, 
int totalMemory, int usedMemory,
+            int totalNumaNodes, int totalVNumaNodes) {
+        FlowPanel summaryPanel = new FlowPanel();
+        CpuSummaryPanel cpuSummaryPanel = this.cpuSummaryPanelProvider.get();
+        cpuSummaryPanel.setName(constants.numaSummaryTotals());
+        cpuSummaryPanel.setCpus(totalCpus, usedCpuPercentage);
+        summaryPanel.add(cpuSummaryPanel);
+
+        MemorySummaryPanel memorySummaryPanel = 
this.memorySummaryPanelProvider.get();
+        memorySummaryPanel.setMemoryStats(totalMemory, usedMemory);
+        summaryPanel.add(memorySummaryPanel);
+
+        summaryPanel.add(new HTML(numaTitleTemplate.title(totalNumaNodes, 
style.hostSummaryNumaTitle())));
+
+        String myImageHtml = 
AbstractImagePrototype.create(resources.vNumaTitleIcon()).getHTML();
+        SafeHtml mySafeImageHtml = new 
OnlyToBeUsedInGeneratedCodeStringBlessedAsSafeHtml(myImageHtml);
+        summaryPanel.add(new HTML(vNumaTitleTemplate.title(totalVNumaNodes, 
mySafeImageHtml,
+                style.hostSummaryNumaTitle())));
+        return summaryPanel;
+    }
+
+    @Override
+    public IsWidget getHostSummaryContent(VDS selectedItem, NumaSupportModel 
supportModel) {
+        HostSummaryContentPanel contentPanel = 
hostSummaryContentProvider.get();
+
+        List<VM> vmsWithVNuma = supportModel.getVmsWithvNumaNodeList();
+        List<VNodeModel> numaNodes = new ArrayList<VNodeModel>();
+        for (VM vm: vmsWithVNuma) {
+            for(VmNumaNode vmNumaNode: vm.getvNumaNodeList()) {
+                VNodeModel vNodeModel = new VNodeModel(supportModel, vm, 
vmNumaNode, false);
+                if (vmNumaNode.getVdsNumaNodeList() != null && 
!vmNumaNode.getVdsNumaNodeList().isEmpty()) {
+                    for (Pair<Guid, Pair<Boolean, Integer>> pair : 
vmNumaNode.getVdsNumaNodeList()) {
+                        if (pair.getSecond().getFirst()) {
+                            vNodeModel.setPinned(true);
+                        }
+                    }
+                }
+                numaNodes.add(vNodeModel);
+            }
+        }
+        contentPanel.setModel(supportModel.getNumaNodeList(), numaNodes);
+        return contentPanel;
+    }
+
+    @Override
+    public void setHostSummaryPanel(IsWidget widget) {
+        this.hostSummaryPanel.add(widget);
+    }
+
+    @Override
+    public void addVNumaInfoPanel(Set<VdsNumaNode> numaNodes, int socketIndex, 
NumaSupportModel supportModel) {
+        SocketPanel socketPanel = socketPanelProvider.get();
+        socketPanel.setHeaderText(messages.numaSocketNumber(socketIndex));
+        for (VdsNumaNode numaNode: numaNodes) {
+            NumaPanel numaPanel = numaPanelProvider.get();
+            
numaPanel.getCpuSummaryPanel().setName(messages.numaNode(numaNode.getIndex()));
+            numaPanel.getCpuSummaryPanel().setCpus(numaNode.getCpuIds().size(),
+                    numaNode.getNumaNodeStatistics().getCpuUsagePercent());
+            
numaPanel.getMemorySummaryPanel().setMemoryStats(numaNode.getMemTotal(),
+                    numaNode.getMemTotal() - 
numaNode.getNumaNodeStatistics().getMemFree());
+            socketPanel.addWidget(numaPanel);
+            AssignedVNumaNodesPanel assignedPanel = 
assignedVNumaPanelProvider.get();
+            
assignedPanel.setNodes(supportModel.getVNumaNodeByNodeId(numaNode.getId()), 
numaNode.getIndex(),
+                    supportModel.getNumaNodeList());
+            socketPanel.addWidget(assignedPanel);
+        }
+        this.socketListPanel.add(socketPanel);
+    }
+
+    @Override
+    public void displayVmDetails(VNodeModel vNodeModel) {
+    }
+
+    @Override
+    public void clear() {
+        this.socketListPanel.clear();
+        this.hostSummaryPanel.clear();
+    }
+}
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/NumaSupportPopupView.ui.xml
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/NumaSupportPopupView.ui.xml
new file mode 100644
index 0000000..9a38b90
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/NumaSupportPopupView.ui.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent";>
+<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
+    xmlns:g="urn:import:com.google.gwt.user.client.ui"
+    xmlns:d="urn:import:org.ovirt.engine.ui.common.widget.dialog"
+    xmlns:ge="urn:import:org.ovirt.engine.ui.common.widget.editor.generic"
+    xmlns:e="urn:import:org.ovirt.engine.ui.common.widget.editor"
+    xmlns:n="urn:import:org.ovirt.engine.ui.common.view.popup.numa">
+
+    <ui:style 
type="org.ovirt.engine.ui.common.view.popup.numa.NumaSupportPopupView.Style">
+        .header {
+            background-color: #EFEFEF;
+        }
+
+        .headerLabel {
+            float: left;
+            font-weight: bolder;
+            font-size: large;
+            line-height: 35px;
+            padding-left: 15px;
+        }
+
+        .hostInfoPanel {
+            margin: 15px 15px 0px 15px;
+            border: 1px solid EFEFEF;
+        }
+
+        .socketScrollPanel {
+            overflow-y: auto;
+        }
+
+        .socketListPanel {
+            float: left;
+        }
+
+        .endFloat {
+            clear: both;
+        }
+
+        .unassignedPanel {
+            background-color: #EDEDED;
+        }
+
+        .hostSummaryNumaTitle {
+            float: left;
+            padding-left: 5px;
+            width: 180px;
+            font-size: medium;
+            color: black;
+            padding: 5px;
+        }
+    </ui:style>
+
+    <d:SimpleDialogPanel width="1200px" height="700px">
+        <d:content>
+            <g:SplitLayoutPanel ui:field="horizontalSplitLayoutPanel">
+                <g:center>
+                    <g:FlowPanel ui:field="groupPanel">
+                        <g:FlowPanel ui:field="hostSummaryPanel" 
addStyleNames="{style.hostInfoPanel}">
+                        </g:FlowPanel>
+                        <g:FlowPanel addStyleNames="{style.socketScrollPanel}">
+                            <g:FlowPanel ui:field="socketListPanel" 
addStyleNames="{style.socketListPanel}"/>
+                        </g:FlowPanel>
+                        <g:SimplePanel addStyleNames="{style.endFloat}" />
+                    </g:FlowPanel>
+                </g:center>
+                <g:east size="300">
+                    <g:FlowPanel ui:field="unassignedvNumaNodesContainer" 
addStyleNames="{style.unassignedPanel}">
+                        <g:HTMLPanel>
+                            <g:Label ui:field="unassignedvNumaNodesLabel" />
+                        </g:HTMLPanel>
+                    </g:FlowPanel>
+                </g:east>
+            </g:SplitLayoutPanel>
+        </d:content>
+    </d:SimpleDialogPanel>
+
+</ui:UiBinder>
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/NumaTitleTemplate.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/NumaTitleTemplate.java
new file mode 100644
index 0000000..de9d89f
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/NumaTitleTemplate.java
@@ -0,0 +1,9 @@
+package org.ovirt.engine.ui.common.view.popup.numa;
+
+import com.google.gwt.safehtml.client.SafeHtmlTemplates;
+import com.google.gwt.safehtml.shared.SafeHtml;
+
+public interface NumaTitleTemplate extends SafeHtmlTemplates {
+    @Template("<div class=\"{1}\">{0} NUMA</div>")
+    SafeHtml title(int count, String className);
+}
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/SocketPanel.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/SocketPanel.java
new file mode 100644
index 0000000..a33fa69
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/SocketPanel.java
@@ -0,0 +1,35 @@
+package org.ovirt.engine.ui.common.view.popup.numa;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.safehtml.shared.SafeHtml;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.IsWidget;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.Widget;
+
+public class SocketPanel extends Composite {
+    interface WidgetUiBinder extends UiBinder<Widget, SocketPanel> {
+        WidgetUiBinder uiBinder = GWT.create(WidgetUiBinder.class);
+    }
+
+    @UiField
+    FlowPanel container;
+
+    @UiField
+    Label headerLabel;
+
+    public SocketPanel() {
+        initWidget(WidgetUiBinder.uiBinder.createAndBindUi(this));
+    }
+
+    public void setHeaderText(SafeHtml text) {
+        headerLabel.setText(text.asString());
+    }
+
+    public void addWidget(IsWidget widget) {
+        container.add(widget);
+    }
+}
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/SocketPanel.ui.xml
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/SocketPanel.ui.xml
new file mode 100644
index 0000000..09f653a
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/SocketPanel.ui.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent";>
+<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" 
xmlns:g="urn:import:com.google.gwt.user.client.ui">
+
+    <ui:style>
+        .header {
+            width: 100%;
+            background-color: #EDEDED;
+            padding-left: 15px;
+            font-weight: bold;
+        }
+
+        .socketPanel {
+            border: 1px #EDEDED solid;
+            width: 260px;
+            float: left;
+            margin-left: 15px;
+            margin-top: 15px;
+        }
+    </ui:style>
+
+    <g:FocusPanel addStyleNames="{style.socketPanel}">
+        <g:FlowPanel>
+            <g:Label ui:field="headerLabel" addStyleNames="{style.header}"/>
+            <g:FlowPanel ui:field="container" />
+        </g:FlowPanel>
+    </g:FocusPanel>
+
+</ui:UiBinder>
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/UnassignedVNumaNodesPanelView.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/UnassignedVNumaNodesPanelView.java
new file mode 100644
index 0000000..e2bae18
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/UnassignedVNumaNodesPanelView.java
@@ -0,0 +1,129 @@
+package org.ovirt.engine.ui.common.view.popup.numa;
+
+import java.util.List;
+
+import org.ovirt.engine.core.common.businessentities.VM;
+import org.ovirt.engine.core.common.businessentities.VdsNumaNode;
+import org.ovirt.engine.ui.common.CommonApplicationConstants;
+import 
org.ovirt.engine.ui.common.presenter.popup.numa.UnassignedVNumaNodesPanelPresenterWidget;
+import org.ovirt.engine.ui.common.view.AbstractView;
+import org.ovirt.engine.ui.uicommonweb.models.hosts.numa.VNodeModel;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.resources.client.CssResource;
+import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.IsWidget;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.gwtplatform.mvp.client.View;
+
+public class UnassignedVNumaNodesPanelView extends AbstractView implements
+    UnassignedVNumaNodesPanelPresenterWidget.ViewDef {
+
+    interface ViewUiBinder extends UiBinder<Widget, 
UnassignedVNumaNodesPanelView> {
+        ViewUiBinder uiBinder = GWT.create(ViewUiBinder.class);
+    }
+
+    interface Style extends CssResource {
+        String scrollPanel();
+
+        String unassignPanel();
+
+        String emptyPanel();
+    }
+
+    private static final int UNASSIGNED = -1; //-1 means unassigned NUMA NODE.
+
+    @UiField
+    Label unassignedHeaderLabel;
+
+    @UiField
+    Label instructionsLabel;
+
+    @UiField
+    FlowPanel unassignedNodesPanel;
+
+    @UiField
+    FlowPanel nodeDetailPanel;
+
+    @UiField
+    Style style;
+
+    @UiField(provided=true)
+    final CommonApplicationConstants commonConstants;
+
+    private final Provider<VmTitlePanel> vmTitlePanelProvider;
+    private final Provider<DraggableVirtualNumaPanel> virtualNumaPanelProvider;
+    private final Provider<DragTargetScrollPanel> scrollPanelProvider;
+
+    /**
+     * Constructor.
+     */
+    @Inject
+    public UnassignedVNumaNodesPanelView(final Provider<VmTitlePanel> 
vmTitlePanelProvider,
+            final Provider<DraggableVirtualNumaPanel> virtualNumaPanelProvider,
+            Provider<DragTargetScrollPanel> scrollPanelProvider, final 
CommonApplicationConstants commonConstants) {
+        this.commonConstants = commonConstants;
+        this.vmTitlePanelProvider = vmTitlePanelProvider;
+        this.virtualNumaPanelProvider = virtualNumaPanelProvider;
+        this.scrollPanelProvider = scrollPanelProvider;
+        initWidget(ViewUiBinder.uiBinder.createAndBindUi(this));
+    }
+
+    private void addVNumaNode(IsWidget widget) {
+        unassignedNodesPanel.add(widget);
+    }
+
+    @Override
+    public void addToUnassignedPanel(View view) {
+        addVNumaNode(view);
+    }
+
+    @Override
+    public IsWidget getNodePanelTitle(VM vm, List<VNodeModel> list) {
+        VmTitlePanel titlePanel = vmTitlePanelProvider.get();
+        SafeHtmlBuilder builder = new SafeHtmlBuilder();
+        builder.appendEscaped(vm.getName());
+        titlePanel.initWidget(builder.toSafeHtml(), list.size(), 
vm.getStatus());
+        return titlePanel;
+    }
+
+    @Override
+    public IsWidget getNodePanelContent(VM vm, List<VNodeModel> virtualNodes, 
List<VdsNumaNode> numaNodeList) {
+        DragTargetScrollPanel scrollPanel = getScrollPanel();
+        scrollPanel.clear();
+        for (VNodeModel nodeModel: virtualNodes) {
+            DraggableVirtualNumaPanel numaNodePanel = 
virtualNumaPanelProvider.get();
+            numaNodePanel.setModel(nodeModel, numaNodeList);
+            scrollPanel.add(numaNodePanel);
+        }
+        if (virtualNodes.isEmpty()) {
+            scrollPanel.addStyleName(style.emptyPanel());
+        }
+        return scrollPanel;
+    }
+
+    @Override
+    public void addEmptyUnassignPanel() {
+        DragTargetScrollPanel scrollPanel = getScrollPanel();
+        scrollPanel.addStyleName(style.unassignPanel());
+        addVNumaNode(scrollPanel);
+    }
+
+    private DragTargetScrollPanel getScrollPanel() {
+        DragTargetScrollPanel scrollPanel = scrollPanelProvider.get();
+        scrollPanel.setStyleName(style.scrollPanel());
+        scrollPanel.setIndex(UNASSIGNED);
+        return scrollPanel;
+    }
+
+    @Override
+    public void clear() {
+        unassignedNodesPanel.clear();
+    }
+}
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/UnassignedVNumaNodesPanelView.ui.xml
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/UnassignedVNumaNodesPanelView.ui.xml
new file mode 100644
index 0000000..3e1fd99
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/UnassignedVNumaNodesPanelView.ui.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent";>
+<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
+    xmlns:g="urn:import:com.google.gwt.user.client.ui">
+
+    <ui:with field="commonConstants" 
type="org.ovirt.engine.ui.common.CommonApplicationConstants" />
+
+    <ui:style 
type="org.ovirt.engine.ui.common.view.popup.numa.UnassignedVNumaNodesPanelView.Style">
+        .unassignedPanelContainer {
+            height: 380px;
+        }
+
+        .unassignedNodesPanel {
+            overflow-y: scroll;
+            background-color: white;
+            border: 1px solid #DADADA;
+            margin: 15px;
+            padding: 5px;
+            height: 260px;
+        }
+
+        .headerLabel {
+            font-size: medium;
+            color: #75797D;
+        }
+
+        .instructionLabel {
+            font-size: smaller;
+            color: #AEAEAE;
+        }
+
+        .labelContainer {
+            padding: 15px;
+        }
+
+        .scrollPanel {
+            background-color: white;
+            overflow-y: auto;
+            height: auto;
+        }
+
+        .unassignPanel {
+            min-height: 75px;
+            margin: 15px;
+            border: 1px dashed #DADADA;
+        }
+
+        .emptyPanel {
+            min-height: 35px;
+            margin-left: 15px;
+            margin-right: 15px;
+            border: 1px dashed #DADADA;
+        }
+    </ui:style>
+
+    <g:FlowPanel addStyleNames="{style.unassignedPanelContainer}">
+        <g:FlowPanel addStyleNames="{style.labelContainer}">
+            <g:Label ui:field="unassignedHeaderLabel" 
addStyleNames="{style.headerLabel}" 
text="{commonConstants.numaUnassignedInstructions}" />
+            <g:Label ui:field="instructionsLabel" 
addStyleNames="{style.instructionLabel}" 
text="{commonConstants.unassignedVNumaNodesLabel}"/>
+        </g:FlowPanel>
+        <g:FlowPanel ui:field="unassignedNodesPanel" 
addStyleNames="{style.unassignedNodesPanel}"/>
+        <g:FlowPanel ui:field="nodeDetailPanel" />
+    </g:FlowPanel>
+</ui:UiBinder>
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/VNumaTitleTemplate.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/VNumaTitleTemplate.java
new file mode 100644
index 0000000..b6f9aa1
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/VNumaTitleTemplate.java
@@ -0,0 +1,9 @@
+package org.ovirt.engine.ui.common.view.popup.numa;
+
+import com.google.gwt.safehtml.client.SafeHtmlTemplates;
+import com.google.gwt.safehtml.shared.SafeHtml;
+
+public interface VNumaTitleTemplate extends SafeHtmlTemplates {
+    @Template("<div class=\"{2}\">{0} {1} vNuma</div>")
+    SafeHtml title(int count, SafeHtml image, String className);
+}
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/VirtualNumaPanel.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/VirtualNumaPanel.java
new file mode 100644
index 0000000..82b4c07
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/VirtualNumaPanel.java
@@ -0,0 +1,154 @@
+package org.ovirt.engine.ui.common.view.popup.numa;
+
+import java.util.Iterator;
+
+import org.ovirt.engine.core.common.businessentities.VMStatus;
+import org.ovirt.engine.ui.common.CommonApplicationMessages;
+import org.ovirt.engine.ui.common.CommonApplicationResources;
+import org.ovirt.engine.ui.uicommonweb.models.hosts.numa.VNodeModel;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.resources.client.ImageResource;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.HasWidgets;
+import com.google.gwt.user.client.ui.Image;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.inject.Inject;
+
+public class VirtualNumaPanel extends Composite implements HasWidgets {
+    interface WidgetUiBinder extends UiBinder<Widget, VirtualNumaPanel> {
+        WidgetUiBinder uiBinder = GWT.create(WidgetUiBinder.class);
+    }
+
+    @UiField(provided=true)
+    final CommonApplicationResources commonResources;
+
+    protected final CommonApplicationMessages messages;
+
+    @UiField
+    FlowPanel container;
+
+    @UiField
+    Image virtualNodeStatus;
+
+    @UiField
+    Image numaState;
+
+    @UiField
+    Label virtualNodeName;
+
+    ImageResource vNumaIcon;
+    ImageResource partialVNumaIcon;
+    ImageResource pinnedVNumaIcon;
+    ImageResource pinnedPartialVNumaIcon;
+
+    @Inject
+    public VirtualNumaPanel(CommonApplicationResources commonResources, 
CommonApplicationMessages messages) {
+        this.commonResources = commonResources;
+        this.messages = messages;
+        initializeResouceIcons(commonResources);
+
+        initWidget(WidgetUiBinder.uiBinder.createAndBindUi(this));
+    }
+
+    private void initializeResouceIcons(CommonApplicationResources resources) {
+        pinnedPartialVNumaIcon = resources.darkPinnedPartialVNumaIcon();
+        pinnedVNumaIcon = resources.darkPinnedVNumaIcon();
+        partialVNumaIcon = resources.darkPartialVNumaIcon();
+        vNumaIcon = resources.darkVNumaIcon();
+    }
+
+    @Override
+    public void setStyleName(String className) {
+        container.setStyleName(className);
+    }
+
+    public void setModel(VNodeModel nodeModel) {
+        
virtualNodeName.setText(messages.vNumaName(nodeModel.getVm().getName(), 
nodeModel.getVmNumaNode().getIndex()));
+        setStatusIcon(nodeModel);
+        setTypeIcon(nodeModel);
+    }
+
+    protected void setStatusIcon(VNodeModel nodeModel) {
+        if (VMStatus.Up.equals(nodeModel.getVm().getStatus())) {
+            virtualNodeStatus.setResource(commonResources.upImage());
+        } else if (VMStatus.Down.equals(nodeModel.getVm().getStatus())) {
+            virtualNodeStatus.setResource(commonResources.downImage());
+        } else {
+            //Unknown status
+            virtualNodeStatus.setResource(commonResources.questionMarkImage());
+        }
+    }
+
+    protected void setTypeIcon(VNodeModel nodeModel) {
+        if (nodeModel.isPinned()) {
+            if (nodeModel.isSplitted()) {
+                numaState.setResource(pinnedPartialVNumaIcon);
+            } else {
+                numaState.setResource(pinnedVNumaIcon);
+            }
+        } else {
+            if (nodeModel.isSplitted()) {
+                numaState.setResource(partialVNumaIcon);
+            } else {
+                numaState.setResource(vNumaIcon);
+            }
+        }
+    }
+
+    public ImageResource getvNumaIcon() {
+        return vNumaIcon;
+    }
+
+    public void setvNumaIcon(ImageResource vNumaIcon) {
+        this.vNumaIcon = vNumaIcon;
+    }
+
+    public ImageResource getPartialVNumaIcon() {
+        return partialVNumaIcon;
+    }
+
+    public void setPartialVNumaIcon(ImageResource partialVNumaIcon) {
+        this.partialVNumaIcon = partialVNumaIcon;
+    }
+
+    public ImageResource getPinnedVNumaIcon() {
+        return pinnedVNumaIcon;
+    }
+
+    public void setPinnedVNumaIcon(ImageResource pinnedVNumaIcon) {
+        this.pinnedVNumaIcon = pinnedVNumaIcon;
+    }
+
+    public ImageResource getPinnedPartialVNumaIcon() {
+        return pinnedPartialVNumaIcon;
+    }
+
+    public void setPinnedPartialVNumaIcon(ImageResource 
pinnedPartialVNumaIcon) {
+        this.pinnedPartialVNumaIcon = pinnedPartialVNumaIcon;
+    }
+
+    @Override
+    public void add(Widget w) {
+        container.insert(w, 0);
+    }
+
+    @Override
+    public void clear() {
+        throw new RuntimeException("Can't clear this widget"); //$NON-NLS-1$
+    }
+
+    @Override
+    public Iterator<Widget> iterator() {
+        return container.iterator();
+    }
+
+    @Override
+    public boolean remove(Widget w) {
+        return container.remove(w);
+    }
+}
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/VirtualNumaPanel.ui.xml
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/VirtualNumaPanel.ui.xml
new file mode 100644
index 0000000..d33c838
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/VirtualNumaPanel.ui.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent";>
+<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" 
xmlns:g="urn:import:com.google.gwt.user.client.ui"
+    xmlns:onu="urn:import:org.ovirt.engine.ui.common.view.popup.numa">
+
+    <ui:with field="commonResources" 
type="org.ovirt.engine.ui.common.CommonApplicationResources" />
+
+    <ui:style>
+        .imageStyle {
+            float: left;
+            padding-left: 5px;
+        }
+
+        .vmStatusIcon {
+            margin-top: 4px;
+        }
+
+        .clearFloat {
+            clear: both;
+        }
+    </ui:style>
+
+    <g:FlowPanel ui:field="container">
+        <g:Image ui:field="virtualNodeStatus" 
resource="{commonResources.downImage}" addStyleNames="{style.imageStyle} 
{style.vmStatusIcon}" />
+        <g:Image ui:field="numaState" resource="{commonResources.vNumaIcon}" 
addStyleNames="{style.imageStyle}" />
+        <g:Label ui:field="virtualNodeName" addStyleNames="{style.imageStyle}" 
/>
+        <g:SimplePanel addStyleNames="{style.clearFloat}" />
+    </g:FlowPanel>
+
+</ui:UiBinder>
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/VmTitlePanel.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/VmTitlePanel.java
new file mode 100644
index 0000000..16a9510
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/VmTitlePanel.java
@@ -0,0 +1,56 @@
+package org.ovirt.engine.ui.common.view.popup.numa;
+
+import org.ovirt.engine.core.common.businessentities.VMStatus;
+import org.ovirt.engine.ui.common.CommonApplicationResources;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.safehtml.shared.SafeHtml;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.Image;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.inject.Inject;
+
+public class VmTitlePanel extends Composite {
+
+    interface WidgetUiBinder extends UiBinder<Widget, VmTitlePanel> {
+        WidgetUiBinder uiBinder = GWT.create(WidgetUiBinder.class);
+    }
+
+    @UiField(provided=true)
+    final CommonApplicationResources commonResources;
+
+    @UiField
+    Image vmStatus;
+
+    @UiField
+    Label vmName;
+
+    @UiField
+    Label nodeCountLabel;
+
+    @Inject
+    public VmTitlePanel(CommonApplicationResources commonResources) {
+        this.commonResources = commonResources;
+        initWidget(WidgetUiBinder.uiBinder.createAndBindUi(this));
+    }
+
+    public void initWidget(SafeHtml vmNameString, int nodeCount, VMStatus 
status) {
+        vmName.setText(vmNameString.asString());
+        nodeCountLabel.setText(String.valueOf(nodeCount));
+        setStatusIcon(status);
+    }
+
+    private void setStatusIcon(VMStatus status) {
+        if (VMStatus.Up.equals(status)) {
+            vmStatus.setResource(commonResources.upImage());
+        } else if (VMStatus.Down.equals(status)) {
+            vmStatus.setResource(commonResources.downImage());
+        } else {
+            //Unknown status
+            vmStatus.setResource(commonResources.questionMarkImage());
+        }
+    }
+}
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/VmTitlePanel.ui.xml
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/VmTitlePanel.ui.xml
new file mode 100644
index 0000000..93b1956
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/view/popup/numa/VmTitlePanel.ui.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent";>
+<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" 
xmlns:g="urn:import:com.google.gwt.user.client.ui">
+
+    <ui:with field="commonResources" 
type="org.ovirt.engine.ui.common.CommonApplicationResources" />
+
+    <ui:style>
+        .container {
+            background-color: white;
+            width: 100%;
+        }
+
+        .itemStyle {
+            float: left;
+            padding-left: 5px;
+        }
+
+        .vmStatusIcon {
+            margin-top: 4px;
+        }
+
+        .nodeCountLabel {
+            float: right;
+            background-color: #B7B7B7;
+            margin: 3px;
+            color: white;
+            min-width: 20px;
+            text-align: center;
+        }
+
+        .clearFloat {
+            clear: both;
+        }
+    </ui:style>
+
+    <g:FlowPanel addStyleNames="{style.container}">
+        <g:Image ui:field="vmStatus" resource="{commonResources.downImage}" 
addStyleNames="{style.itemStyle} {style.vmStatusIcon}" />
+        <g:Label ui:field="vmName" addStyleNames="{style.itemStyle}" />
+        <g:SimplePanel addStyleNames="{style.nodeCountLabel}">
+            <g:Label ui:field="nodeCountLabel" />
+        </g:SimplePanel>
+        <g:SimplePanel addStyleNames="{style.clearFloat}" />
+    </g:FlowPanel>
+</ui:UiBinder>
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/collapsed_header_icon.png
 
b/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/collapsed_header_icon.png
new file mode 100644
index 0000000..94ca3bc
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/collapsed_header_icon.png
Binary files differ
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/expanded_header_icon.png
 
b/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/expanded_header_icon.png
new file mode 100644
index 0000000..3a8dc18
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/expanded_header_icon.png
Binary files differ
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/drag_handle.png
 
b/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/drag_handle.png
new file mode 100644
index 0000000..25f3a39
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/drag_handle.png
Binary files differ
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/partial_vnuma_dark_icon.png
 
b/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/partial_vnuma_dark_icon.png
new file mode 100644
index 0000000..fdf9a77
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/partial_vnuma_dark_icon.png
Binary files differ
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/partial_vnuma_light_icon.png
 
b/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/partial_vnuma_light_icon.png
new file mode 100644
index 0000000..f9b1eb5
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/partial_vnuma_light_icon.png
Binary files differ
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/pinned_partial_vnuma_dark_icon.png
 
b/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/pinned_partial_vnuma_dark_icon.png
new file mode 100644
index 0000000..8eb1624
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/pinned_partial_vnuma_dark_icon.png
Binary files differ
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/pinned_partial_vnuma_light_icon.png
 
b/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/pinned_partial_vnuma_light_icon.png
new file mode 100644
index 0000000..ce3efdc
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/pinned_partial_vnuma_light_icon.png
Binary files differ
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/pinned_vnuma_dark_icon.png
 
b/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/pinned_vnuma_dark_icon.png
new file mode 100644
index 0000000..775b6e8
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/pinned_vnuma_dark_icon.png
Binary files differ
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/pinned_vnuma_light_icon.png
 
b/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/pinned_vnuma_light_icon.png
new file mode 100644
index 0000000..0850b18
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/pinned_vnuma_light_icon.png
Binary files differ
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/vnuma_dark_icon.png
 
b/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/vnuma_dark_icon.png
new file mode 100644
index 0000000..b743e18
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/vnuma_dark_icon.png
Binary files differ
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/vnuma_icon.png
 
b/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/vnuma_icon.png
new file mode 100644
index 0000000..233ded6
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/vnuma_icon.png
Binary files differ
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/vnuma_light_icon.png
 
b/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/vnuma_light_icon.png
new file mode 100644
index 0000000..e740cf0
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/resources/org/ovirt/engine/ui/common/images/numa/vnuma_light_icon.png
Binary files differ
diff --git 
a/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/dataprovider/AsyncDataProvider.java
 
b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/dataprovider/AsyncDataProvider.java
index 4bd10b5..2f80c4d 100644
--- 
a/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/dataprovider/AsyncDataProvider.java
+++ 
b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/dataprovider/AsyncDataProvider.java
@@ -37,6 +37,7 @@
 import org.ovirt.engine.core.common.businessentities.IVdcQueryable;
 import org.ovirt.engine.core.common.businessentities.ImageFileType;
 import org.ovirt.engine.core.common.businessentities.LUNs;
+import org.ovirt.engine.core.common.businessentities.NumaTuneMode;
 import org.ovirt.engine.core.common.businessentities.Permissions;
 import org.ovirt.engine.core.common.businessentities.Provider;
 import org.ovirt.engine.core.common.businessentities.ProviderType;
@@ -57,6 +58,7 @@
 import org.ovirt.engine.core.common.businessentities.VDSGroup;
 import org.ovirt.engine.core.common.businessentities.VDSStatus;
 import org.ovirt.engine.core.common.businessentities.VM;
+import org.ovirt.engine.core.common.businessentities.VdsNumaNode;
 import org.ovirt.engine.core.common.businessentities.VmGuestAgentInterface;
 import org.ovirt.engine.core.common.businessentities.VmPool;
 import org.ovirt.engine.core.common.businessentities.VmTemplate;
@@ -84,8 +86,8 @@
 import org.ovirt.engine.core.common.businessentities.profiles.DiskProfile;
 import org.ovirt.engine.core.common.interfaces.SearchType;
 import org.ovirt.engine.core.common.mode.ApplicationMode;
-import 
org.ovirt.engine.core.common.queries.ArchCapabilitiesParameters.ArchCapabilitiesVerb;
 import org.ovirt.engine.core.common.queries.ArchCapabilitiesParameters;
+import 
org.ovirt.engine.core.common.queries.ArchCapabilitiesParameters.ArchCapabilitiesVerb;
 import org.ovirt.engine.core.common.queries.CommandVersionsInfo;
 import org.ovirt.engine.core.common.queries.ConfigurationValues;
 import 
org.ovirt.engine.core.common.queries.GetAgentFenceOptionsQueryParameters;
@@ -115,8 +117,8 @@
 import org.ovirt.engine.core.common.queries.InterfaceAndIdQueryParameters;
 import 
org.ovirt.engine.core.common.queries.MultilevelAdministrationsQueriesParameters;
 import org.ovirt.engine.core.common.queries.NameQueryParameters;
-import org.ovirt.engine.core.common.queries.OsQueryParameters.OsRepositoryVerb;
 import org.ovirt.engine.core.common.queries.OsQueryParameters;
+import org.ovirt.engine.core.common.queries.OsQueryParameters.OsRepositoryVerb;
 import org.ovirt.engine.core.common.queries.ProviderQueryParameters;
 import org.ovirt.engine.core.common.queries.SearchParameters;
 import org.ovirt.engine.core.common.queries.ServerParameters;
@@ -3806,4 +3808,43 @@
         };
     }
 
+    public static void getHostNumaTopologyByHostId(AsyncQuery asyncQuery, Guid 
hostId) {
+        asyncQuery.converterCallback = new IAsyncConverter() {
+
+            @Override
+            public Object Convert(Object source, AsyncQuery asyncQuery) {
+                if (source == null) {
+                    return new ArrayList<VdsNumaNode>();
+                }
+                return source;
+            }
+        };
+        Frontend.getInstance().runQuery(VdcQueryType.GetVdsNumaNodesByVdsId,
+                new IdQueryParameters(hostId),
+                asyncQuery);
+    }
+
+    public static void getVMsWithVNumaNodesByClusterId(AsyncQuery asyncQuery, 
Guid clusterId) {
+        asyncQuery.converterCallback = new IAsyncConverter() {
+
+            @Override
+            public Object Convert(Object source, AsyncQuery asyncQuery) {
+                if (source == null) {
+                    return new ArrayList<VM>();
+                }
+                return source;
+            }
+        };
+        
Frontend.getInstance().runQuery(VdcQueryType.GetAllVmsWithNumaByVdsGroupId,
+                new IdQueryParameters(clusterId),
+                asyncQuery);
+    }
+
+    public static ArrayList<NumaTuneMode> getNumaTuneModeList() {
+        return new ArrayList<NumaTuneMode>(Arrays.asList(new NumaTuneMode[] {
+                NumaTuneMode.STRICT,
+                NumaTuneMode.PREFERRED,
+                NumaTuneMode.INTERLEAVE
+        }));
+    }
 }
diff --git 
a/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/help/HelpTag.java
 
b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/help/HelpTag.java
index 05ebc6d..626f0fa 100644
--- 
a/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/help/HelpTag.java
+++ 
b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/help/HelpTag.java
@@ -510,7 +510,9 @@
 
     edit_cpu_profile("edit_cpu_profile", HelpTagType.WEBADMIN, "Cluster Tab > 
Cpu Profiles sub-tab -> Edit Cpu Profile dialog"), //$NON-NLS-1$ //$NON-NLS-2$
 
-    remove_cpu_profile("remove_cpu_profile", HelpTagType.WEBADMIN, "Clsuter 
Tab > Cpu Profiles sub-tab -> Remove Cpu Profile dialog"); //$NON-NLS-1$ 
//$NON-NLS-2$
+    remove_cpu_profile("remove_cpu_profile", HelpTagType.WEBADMIN, "Clsuter 
Tab > Cpu Profiles sub-tab -> Remove Cpu Profile dialog"), //$NON-NLS-1$ 
//$NON-NLS-2$
+
+    numa_support("numa_support", HelpTagType.WEBADMIN, "Hosts maint tab -> 
NUMA Support"); //$NON-NLS-1$ //$NON-NLS-2$
 
     public final String name;
 
diff --git 
a/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/hosts/HostListModel.java
 
b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/hosts/HostListModel.java
index 430664d..6dd6870 100644
--- 
a/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/hosts/HostListModel.java
+++ 
b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/hosts/HostListModel.java
@@ -40,8 +40,10 @@
 import org.ovirt.engine.core.common.businessentities.VDSGroup;
 import org.ovirt.engine.core.common.businessentities.VDSStatus;
 import org.ovirt.engine.core.common.businessentities.VDSType;
+import org.ovirt.engine.core.common.businessentities.VM;
 import org.ovirt.engine.core.common.businessentities.VdsProtocol;
 import org.ovirt.engine.core.common.businessentities.VdsSpmStatus;
+import org.ovirt.engine.core.common.businessentities.VmNumaNode;
 import org.ovirt.engine.core.common.businessentities.aaa.DbUser;
 import org.ovirt.engine.core.common.interfaces.SearchType;
 import org.ovirt.engine.core.common.mode.ApplicationMode;
@@ -76,6 +78,7 @@
 import org.ovirt.engine.ui.uicommonweb.models.events.TaskListModel;
 import org.ovirt.engine.ui.uicommonweb.models.gluster.GlusterFeaturesUtil;
 import 
org.ovirt.engine.ui.uicommonweb.models.gluster.HostGlusterSwiftListModel;
+import org.ovirt.engine.ui.uicommonweb.models.hosts.numa.NumaSupportModel;
 import org.ovirt.engine.ui.uicommonweb.models.tags.TagListModel;
 import org.ovirt.engine.ui.uicommonweb.models.tags.TagModel;
 import org.ovirt.engine.ui.uicompat.ConstantsManager;
@@ -303,6 +306,16 @@
         refreshCapabilitiesCommand = value;
     }
 
+    private UICommand numaSupportCommand;
+
+    public UICommand getNumaSupportCommand() {
+        return numaSupportCommand;
+    }
+
+    public void setNumaSupportCommand(UICommand numaSupportCommand) {
+        this.numaSupportCommand = numaSupportCommand;
+    }
+
     private HostEventListModel privateHostEventListModel;
 
     private HostEventListModel getHostEventListModel()
@@ -405,7 +418,7 @@
         setAssignTagsCommand(new UICommand("AssignTags", this)); //$NON-NLS-1$
         setConfigureLocalStorageCommand(new UICommand("ConfigureLocalStorage", 
this)); //$NON-NLS-1$
         setRefreshCapabilitiesCommand(new UICommand("GetCapabilities", this)); 
//$NON-NLS-1$
-
+        setNumaSupportCommand(new UICommand("NumaSupport", this)); 
//$NON-NLS-1$
         
getConfigureLocalStorageCommand().setAvailableInModes(ApplicationMode.VirtOnly);
         getSelectAsSpmCommand().setAvailableInModes(ApplicationMode.VirtOnly);
         updateActionAvailability();
@@ -2076,6 +2089,13 @@
         getRefreshCapabilitiesCommand().setIsExecutionAllowed(items.size() > 0 
&& VdcActionUtils.canExecute(items,
                 VDS.class,
                 VdcActionType.RefreshHostCapabilities));
+
+        boolean numaVisible = false;
+        if (getSelectedItem() != null) {
+            numaVisible = ((VDS) getSelectedItem()).isNumaSupport();
+        }
+        getNumaSupportCommand().setIsVisible(numaVisible);
+
     }
 
     private Boolean hasAdminSystemPermission = null;
@@ -2213,6 +2233,9 @@
         {
             refreshCapabilities();
         }
+        else if (command == getNumaSupportCommand()) {
+            numaSupport();
+        }
         else if ("OnAssignTags".equals(command.getName())) //$NON-NLS-1$
         {
             onAssignTags();
@@ -2277,6 +2300,43 @@
         {
             onConfigureLocalStorage();
         }
+        else if 
(NumaSupportModel.SUBMIT_NUMA_SUPPORT.equals(command.getName())) {
+            onNumaSupport();
+        }
+    }
+
+    private void numaSupport() {
+        if (getWindow() != null) {
+            return;
+        }
+
+        VDS host = (VDS) getSelectedItem();
+        List<VDS> hosts = getSelectedItems();
+
+        NumaSupportModel model = new NumaSupportModel(hosts, host, this);
+        setWindow(model);
+    }
+
+    private void onNumaSupport() {
+        if (getWindow() == null) {
+            return;
+        }
+        NumaSupportModel model = (NumaSupportModel) getWindow();
+        ArrayList<VdcActionParametersBase> updateParamsList = 
model.getUpdateParameters();
+        if (!updateParamsList.isEmpty()) {
+            
Frontend.getInstance().runMultipleAction(VdcActionType.UpdateVmNumaNodes, 
updateParamsList);
+        }
+        setWindow(null);
+    }
+
+    private void updateVNodesMap(VM vm, Map<Guid, VmNumaNode> map) {
+        List<VmNumaNode> list = new ArrayList<VmNumaNode>();
+        for (VmNumaNode node : vm.getvNumaNodeList()) {
+            list.add(node);
+        }
+        for (VmNumaNode node : list) {
+            map.put(node.getId(), node);
+        }
     }
 
     private void selectAsSPM() {
diff --git 
a/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/hosts/numa/NumaSupportModel.java
 
b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/hosts/numa/NumaSupportModel.java
new file mode 100644
index 0000000..c5d3a57
--- /dev/null
+++ 
b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/hosts/numa/NumaSupportModel.java
@@ -0,0 +1,302 @@
+package org.ovirt.engine.ui.uicommonweb.models.hosts.numa;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.ovirt.engine.core.common.action.VdcActionParametersBase;
+import org.ovirt.engine.core.common.action.VmNumaNodeOperationParameters;
+import org.ovirt.engine.core.common.businessentities.VDS;
+import org.ovirt.engine.core.common.businessentities.VM;
+import org.ovirt.engine.core.common.businessentities.VdsNumaNode;
+import org.ovirt.engine.core.common.businessentities.VmNumaNode;
+import org.ovirt.engine.core.common.utils.Pair;
+import org.ovirt.engine.core.compat.Guid;
+import org.ovirt.engine.ui.frontend.AsyncQuery;
+import org.ovirt.engine.ui.frontend.INewAsyncCallback;
+import org.ovirt.engine.ui.uicommonweb.UICommand;
+import org.ovirt.engine.ui.uicommonweb.dataprovider.AsyncDataProvider;
+import org.ovirt.engine.ui.uicommonweb.help.HelpTag;
+import org.ovirt.engine.ui.uicommonweb.models.ListModel;
+import org.ovirt.engine.ui.uicommonweb.models.Model;
+import org.ovirt.engine.ui.uicompat.ConstantsManager;
+import org.ovirt.engine.ui.uicompat.Event;
+import org.ovirt.engine.ui.uicompat.EventArgs;
+import org.ovirt.engine.ui.uicompat.EventDefinition;
+import org.ovirt.engine.ui.uicompat.IEventListener;
+
+public class NumaSupportModel extends Model {
+
+    public static final String SUBMIT_NUMA_SUPPORT = "SubmitNumaSupport"; 
//$NON-NLS-1$
+    private final Model parentModel;
+    private ListModel<VDS> hosts;
+    private List<VdsNumaNode> numaNodeList;
+    private List<VM> vmsWithvNumaNodeList;
+    private List<VNodeModel> unassignedVNodeModelList;
+    private Map<Guid, List<VNodeModel>> p2vNumaNodesMap;
+    private List<Pair<Integer, Set<VdsNumaNode>>> firstLevelDistanceSetList;
+    private final Event modelReady = new Event(new 
EventDefinition("ModelReady", NumaSupportModel.class)); //$NON-NLS-1$
+    private Map<Integer, VdsNumaNode> indexNodeMap;
+    private final Map<Guid, VdcActionParametersBase> updateParametersMap = new 
HashMap<Guid, VdcActionParametersBase>();
+
+    public NumaSupportModel(List<VDS> hosts, VDS host, Model parentModel) {
+        this.parentModel = parentModel;
+        setHosts(new ListModel<VDS>());
+        setNumaNodeList(new ArrayList<VdsNumaNode>());
+        
setTitle(ConstantsManager.getInstance().getMessages().numaTopologyTitle(host.getName()));
+        setHelpTag(HelpTag.numa_support);
+        setHashName("numa_support"); //$NON-NLS-1$
+        initCommands();
+        initHosts(hosts, host);
+    }
+
+    private void initHosts(List<VDS> hosts, VDS host) {
+        getHosts().setItems(hosts);
+        if (host == null) {
+            host = hosts.get(0);
+        }
+        if (getHosts().getItems().size() <= 1) {
+            getHosts().setIsChangable(false);
+        }
+        getHosts().getSelectedItemChangedEvent().addListener(new 
IEventListener() {
+
+            @Override
+            public void eventRaised(Event ev, Object sender, EventArgs args) {
+                initHostNUMATopology();
+            }
+        });
+        getHosts().setSelectedItem(host);
+    }
+
+    protected void initCommands() {
+        UICommand command = new UICommand(SUBMIT_NUMA_SUPPORT, this);
+        command.setTitle(ConstantsManager.getInstance().getConstants().ok());
+        getCommands().add(command);
+
+        command = new UICommand("Cancel", this); //$NON-NLS-1$
+        
command.setTitle(ConstantsManager.getInstance().getConstants().cancel());
+        command.setIsCancel(true);
+        command.setIsDefault(true);
+        getCommands().add(command);
+    }
+
+    protected void initHostNUMATopology() {
+        startProgress(null);
+        AsyncDataProvider.getHostNumaTopologyByHostId(new AsyncQuery(new 
INewAsyncCallback() {
+
+            @SuppressWarnings("unchecked")
+            @Override
+            public void onSuccess(Object model, Object returnValue) {
+                // TODO: host query can be skipped in case it was already 
fetched.
+                
NumaSupportModel.this.getNumaNodeList().addAll((List<VdsNumaNode>) returnValue);
+                NumaSupportModel.this.initFirstLevelDistanceSetList();
+                AsyncDataProvider.getVMsWithVNumaNodesByClusterId(new 
AsyncQuery(new INewAsyncCallback() {
+
+                    @Override
+                    public void onSuccess(Object model, Object returnValue) {
+                        
NumaSupportModel.this.setVmsWithvNumaNodeList((List<VM>) returnValue);
+                        NumaSupportModel.this.modelReady();
+                    }
+
+                }), 
NumaSupportModel.this.hosts.getSelectedItem().getVdsGroupId());
+            }
+
+        }), hosts.getSelectedItem().getId());
+    }
+
+    private void initVNumaNodes() {
+        unassignedVNodeModelList = new ArrayList<VNodeModel>();
+        p2vNumaNodesMap = new HashMap<Guid, List<VNodeModel>>();
+
+        for (VM vm : getVmsWithvNumaNodeList()) {
+            if (vm.getvNumaNodeList() != null) {
+                for (VmNumaNode vmNumaNode : vm.getvNumaNodeList()) {
+                    VNodeModel vNodeModel = new VNodeModel(this, vm, 
vmNumaNode, false);
+                    if (vmNumaNode.getVdsNumaNodeList() != null && 
!vmNumaNode.getVdsNumaNodeList().isEmpty()) {
+                        for (Pair<Guid, Pair<Boolean, Integer>> pair : 
vmNumaNode.getVdsNumaNodeList()) {
+                            if (!pair.getSecond().getFirst()) {
+                                unassignedVNodeModelList.add(vNodeModel);
+                                break;
+                            } else {
+                                vNodeModel.setPinned(true);
+                                Guid nodeId = pair.getFirst();
+                                assignVNumaToPhysicalNuma(vNodeModel, nodeId);
+                            }
+                        }
+                    } else {
+                        unassignedVNodeModelList.add(vNodeModel);
+                    }
+                }
+            }
+        }
+    }
+
+    private void assignVNumaToPhysicalNuma(VNodeModel vNodeModel, Guid nodeId) 
{
+        if (!p2vNumaNodesMap.containsKey(nodeId)) {
+            p2vNumaNodesMap.put(nodeId, new ArrayList<VNodeModel>());
+        }
+        p2vNumaNodesMap.get(nodeId)
+                .add(vNodeModel);
+    }
+
+    private VdsNumaNode getNodeByIndex(Integer index) {
+        if (indexNodeMap == null) {
+            indexNodeMap = new HashMap<Integer, VdsNumaNode>();
+            for (VdsNumaNode node : getNumaNodeList()) {
+                indexNodeMap.put(node.getIndex(), node);
+            }
+        }
+        return indexNodeMap.get(index);
+    }
+
+    public List<VNodeModel> getVNumaNodeByNodeId(Guid nodeId) {
+        return p2vNumaNodesMap.get(nodeId);
+    }
+
+    private void initFirstLevelDistanceSetList() {
+        firstLevelDistanceSetList = new ArrayList<Pair<Integer, 
Set<VdsNumaNode>>>();
+        for (VdsNumaNode node : getNumaNodeList()) {
+            Map<Integer, Set<VdsNumaNode>> distances = new HashMap<Integer, 
Set<VdsNumaNode>>();
+            for (Entry<Integer, Integer> entry : 
node.getNumaNodeDistances().entrySet()) {
+                Set<VdsNumaNode> sameDistanceNodes = 
distances.get(entry.getValue());
+                if (sameDistanceNodes == null) {
+                    sameDistanceNodes = new HashSet<VdsNumaNode>();
+                    sameDistanceNodes.add(getNodeByIndex(entry.getKey()));
+                    distances.put(entry.getValue(), sameDistanceNodes);
+                }
+                sameDistanceNodes.add(node);
+            }
+
+            Entry<Integer, Set<VdsNumaNode>> minDistance = null;
+            for (Entry<Integer, Set<VdsNumaNode>> entry : 
distances.entrySet()) {
+                if (minDistance == null || entry.getKey() < 
minDistance.getKey()) {
+                    minDistance = entry;
+                }
+            }
+
+            boolean found = false;
+            for (Pair<Integer, Set<VdsNumaNode>> group : 
firstLevelDistanceSetList) {
+                // 'true' if the two specified collections have no elements in 
common
+                boolean isDisjoint = Collections.disjoint(group.getSecond(), 
minDistance.getValue());
+                if (group.getFirst().equals(minDistance.getKey()) && 
!isDisjoint) {
+                    group.getSecond().addAll(minDistance.getValue());
+                    found = true;
+                    break;
+                }
+            }
+            if (!found && minDistance != null) {
+                firstLevelDistanceSetList.add(new Pair<Integer, 
Set<VdsNumaNode>>(minDistance.getKey(),
+                        minDistance.getValue()));
+            }
+        }
+    }
+
+    private void modelReady() {
+        initVNumaNodes();
+        getModelReady().raise(this, EventArgs.EMPTY);
+        stopProgress();
+    }
+
+    public void cancel() {
+        parentModel.setWindow(null);
+    }
+
+    public List<VdsNumaNode> getNumaNodeList() {
+        return numaNodeList;
+    }
+
+    public void setNumaNodeList(List<VdsNumaNode> numaNodeList) {
+        this.numaNodeList = numaNodeList;
+    }
+
+    public List<VM> getVmsWithvNumaNodeList() {
+        return vmsWithvNumaNodeList;
+    }
+
+    public void setVmsWithvNumaNodeList(List<VM> vmsWithvNumaNodeList) {
+        this.vmsWithvNumaNodeList = vmsWithvNumaNodeList;
+    }
+
+    public List<VNodeModel> getUnassignedVNodeModelList() {
+        return unassignedVNodeModelList;
+    }
+
+    public List<Pair<Integer, Set<VdsNumaNode>>> 
getFirstLevelDistanceSetList() {
+        return firstLevelDistanceSetList;
+    }
+
+    public void setFirstLevelDistanceSetList(List<Pair<Integer, 
Set<VdsNumaNode>>> firstLevelDistanceSetList) {
+        this.firstLevelDistanceSetList = firstLevelDistanceSetList;
+    }
+
+    public Event getModelReady() {
+        return modelReady;
+    }
+
+    public ListModel<VDS> getHosts() {
+        return hosts;
+    }
+
+    public void setHosts(ListModel<VDS> hosts) {
+        this.hosts = hosts;
+    }
+
+    @Override
+    public void executeCommand(UICommand command) {
+        super.executeCommand(command);
+        if (SUBMIT_NUMA_SUPPORT.equals(command.getName())) {
+            parentModel.executeCommand(command);
+            parentModel.setWindow(null);
+        } else if ("Cancel".equals(command.getName())) { //$NON-NLS-1$
+            cancel();
+        }
+    }
+
+    public void pinVNodeToNumaNode(Guid sourceVMGuid, boolean isPinned, int 
sourceVNumaIndex, int targetPNumaNodeIndex) {
+        boolean breakFlag = false;
+        for (VM vm : getVmsWithvNumaNodeList()) {
+            if (vm.getId().equals(sourceVMGuid)) {
+                for (VmNumaNode vmNumaNode : vm.getvNumaNodeList()) {
+                    if (vmNumaNode.getIndex() == sourceVNumaIndex) {
+                        breakFlag = true;
+                        if (vmNumaNode.getVdsNumaNodeList().isEmpty()) {
+                            Pair<Guid, Pair<Boolean, Integer>> pair = new 
Pair<Guid, Pair<Boolean, Integer>>();
+                            
pair.setFirst(getNodeByIndex(targetPNumaNodeIndex).getId());
+                            pair.setSecond(new Pair<Boolean, Integer>());
+                            pair.getSecond().setFirst(true);
+                            pair.getSecond().setSecond(targetPNumaNodeIndex);
+                            vmNumaNode.getVdsNumaNodeList().add(pair);
+                        } else {
+                            for (Pair<Guid, Pair<Boolean, Integer>> pair : 
vmNumaNode.getVdsNumaNodeList()) {
+                                if (targetPNumaNodeIndex == -1) {
+                                    pair.setFirst(null);
+                                    pair.getSecond().setFirst(false);
+                                } else {
+                                    
pair.setFirst(getNodeByIndex(targetPNumaNodeIndex).getId());
+                                    pair.getSecond().setFirst(true);
+                                    
pair.getSecond().setSecond(targetPNumaNodeIndex);
+                                }
+                            }
+                        }
+                        break;
+                    }
+                }
+                updateParametersMap.put(vm.getId(),
+                        new VmNumaNodeOperationParameters(vm.getId(), 
vm.getvNumaNodeList()));
+            }
+            if (breakFlag) {
+                break;
+            }
+        }
+        modelReady();
+    }
+
+    public ArrayList<VdcActionParametersBase> getUpdateParameters() {
+        return new 
ArrayList<VdcActionParametersBase>(updateParametersMap.values());
+    }
+}
diff --git 
a/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/hosts/numa/VNodeModel.java
 
b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/hosts/numa/VNodeModel.java
new file mode 100644
index 0000000..dbf3909
--- /dev/null
+++ 
b/frontend/webadmin/modules/uicommonweb/src/main/java/org/ovirt/engine/ui/uicommonweb/models/hosts/numa/VNodeModel.java
@@ -0,0 +1,43 @@
+package org.ovirt.engine.ui.uicommonweb.models.hosts.numa;
+
+import org.ovirt.engine.core.common.businessentities.VM;
+import org.ovirt.engine.core.common.businessentities.VmNumaNode;
+import org.ovirt.engine.ui.uicommonweb.models.Model;
+
+public class VNodeModel extends Model {
+    private final NumaSupportModel numaSupportModel;
+    private final VM vm;
+    private final VmNumaNode vmNumaNode;
+    private boolean pinned;
+
+    public VNodeModel(NumaSupportModel numaSupportModel, VM vm, VmNumaNode 
vmNumaNode, boolean pinned) {
+        this.numaSupportModel = numaSupportModel;
+        this.vm = vm;
+        this.vmNumaNode = vmNumaNode;
+        this.pinned = pinned;
+    }
+
+    public NumaSupportModel getNumaSupportModel() {
+        return numaSupportModel;
+    }
+
+    public VM getVm() {
+        return vm;
+    }
+
+    public VmNumaNode getVmNumaNode() {
+        return vmNumaNode;
+    }
+
+    public boolean isPinned() {
+        return pinned;
+    }
+
+    public void setPinned(boolean pinned) {
+        this.pinned = pinned;
+    }
+
+    public boolean isSplitted() {
+        return getVmNumaNode().getVdsNumaNodeList() != null && 
getVmNumaNode().getVdsNumaNodeList().size() > 1;
+    }
+}
diff --git 
a/frontend/webadmin/modules/uicompat/src/main/java/org/ovirt/engine/ui/uicompat/UIMessages.java
 
b/frontend/webadmin/modules/uicompat/src/main/java/org/ovirt/engine/ui/uicompat/UIMessages.java
index 42c154f..51cb0e8 100644
--- 
a/frontend/webadmin/modules/uicompat/src/main/java/org/ovirt/engine/ui/uicompat/UIMessages.java
+++ 
b/frontend/webadmin/modules/uicompat/src/main/java/org/ovirt/engine/ui/uicompat/UIMessages.java
@@ -313,6 +313,9 @@
     @DefaultMessage("{0} ({1} Socket(s), {2} Core(s) per Socket)")
     String cpuInfoMessage(int numOfCpus, int sockets, int coresPerSocket);
 
+    @DefaultMessage("NUMA Topology - {0}")
+    String numaTopologyTitle(String hostName);
+
     @DefaultMessage("Could not fetch rebalance status of volume :  {0}")
     String rebalanceStatusFailed(String name);
 
diff --git 
a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/ApplicationConstants.java
 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/ApplicationConstants.java
index 5831272..cbe22cf 100644
--- 
a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/ApplicationConstants.java
+++ 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/ApplicationConstants.java
@@ -3707,6 +3707,7 @@
     @DefaultStringValue("Disk Snapshots")
     String snapshotsLabel();
 
+
     @DefaultStringValue("Attached by label")
     String attachedByLabel();
 
@@ -3857,4 +3858,7 @@
 
     @DefaultStringValue("QoS")
     String cpuProfileQosLabel();
+
+    @DefaultStringValue("NUMA Support")
+    String numaSupport();
 }
diff --git 
a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/ApplicationMessages.java
 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/ApplicationMessages.java
index 99dbb60..3963747 100644
--- 
a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/ApplicationMessages.java
+++ 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/ApplicationMessages.java
@@ -106,4 +106,5 @@
 
     @DefaultMessage("Default ({0})")
     String defaultMtu(int mtu);
+
 }
diff --git 
a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/ApplicationResources.java
 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/ApplicationResources.java
index 4d67455..848d8cd 100644
--- 
a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/ApplicationResources.java
+++ 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/ApplicationResources.java
@@ -426,5 +426,4 @@
 
     @Source("images/glusterAsyncTasks/remove_brick_commit_required.png")
     ImageResource removeBrickCommitRequired();
-
 }
diff --git 
a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/gin/uicommon/HostModule.java
 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/gin/uicommon/HostModule.java
index df8c076..9e1565d 100644
--- 
a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/gin/uicommon/HostModule.java
+++ 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/gin/uicommon/HostModule.java
@@ -14,6 +14,7 @@
 import 
org.ovirt.engine.ui.common.presenter.popup.DefaultConfirmationPopupPresenterWidget;
 import 
org.ovirt.engine.ui.common.presenter.popup.RemoveConfirmationPopupPresenterWidget;
 import 
org.ovirt.engine.ui.common.presenter.popup.RolePermissionsRemoveConfirmationPopupPresenterWidget;
+import 
org.ovirt.engine.ui.common.presenter.popup.numa.NumaSupportPopupPresenterWidget;
 import org.ovirt.engine.ui.common.uicommon.model.DetailModelProvider;
 import org.ovirt.engine.ui.common.uicommon.model.DetailTabModelProvider;
 import org.ovirt.engine.ui.common.uicommon.model.MainModelProvider;
@@ -80,7 +81,8 @@
             final Provider<AssignTagsPopupPresenterWidget> 
assignTagsPopupProvider,
             final Provider<ReportPresenterWidget> reportWindowProvider,
             final Provider<ConfigureLocalStoragePopupPresenterWidget> 
configureLocalStoragePopupProvider,
-            final Provider<HostInstallPopupPresenterWidget> 
installPopupProvider) {
+            final Provider<HostInstallPopupPresenterWidget> 
installPopupProvider,
+            final Provider<NumaSupportPopupPresenterWidget> 
numaSupportPopupProvider) {
         return new MainTabModelProvider<VDS, HostListModel>(eventBus, 
defaultConfirmPopupProvider, HostListModel.class) {
             @Override
             public AbstractModelBoundPopupPresenterWidget<? extends Model, ?> 
getModelPopup(HostListModel source,
@@ -97,6 +99,8 @@
                     return assignTagsPopupProvider.get();
                 } else if (lastExecutedCommand == 
getModel().getConfigureLocalStorageCommand()) {
                     return configureLocalStoragePopupProvider.get();
+                } else if (lastExecutedCommand == 
getModel().getNumaSupportCommand()) {
+                    return numaSupportPopupProvider.get();
                 }
                 return super.getModelPopup(source, lastExecutedCommand, 
windowModel);
             }
diff --git 
a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/tab/MainTabHostView.java
 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/tab/MainTabHostView.java
index cebae83..cda3b0e 100644
--- 
a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/tab/MainTabHostView.java
+++ 
b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/tab/MainTabHostView.java
@@ -245,6 +245,12 @@
             }
         });
         if (ApplicationModeHelper.getUiMode() != ApplicationMode.GlusterOnly) {
+            getTable().addActionButton(new 
WebAdminButtonDefinition<VDS>(constants.numaSupport()) {
+                @Override
+                protected UICommand resolveCommand() {
+                    return getMainModel().getNumaSupportCommand();
+                }
+            });
             getTable().addActionButton(new 
WebAdminButtonDefinition<VDS>(constants.confirmRebootedHost(),
                     CommandLocation.OnlyFromContext) {
                 @Override


-- 
To view, visit http://gerrit.ovirt.org/33193
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I0712ea82b87d4fe9fc25f196183136485c0c4381
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-engine
Gerrit-Branch: ovirt-engine-3.5
Gerrit-Owner: Gilad Chaplik <gchap...@redhat.com>
_______________________________________________
Engine-patches mailing list
Engine-patches@ovirt.org
http://lists.ovirt.org/mailman/listinfo/engine-patches

Reply via email to