diff --git a/circle/circle/settings/base.py b/circle/circle/settings/base.py
index 79ae63c..3e7b86e 100644
--- a/circle/circle/settings/base.py
+++ b/circle/circle/settings/base.py
@@ -431,9 +431,18 @@ LOGIN_REDIRECT_URL = "/"
 
 AGENT_DIR = get_env_variable(
     'DJANGO_AGENT_DIR', join(unicode(expanduser("~")), 'agent'))
+    # AGENT_DIR is the root directory for the agent.
+    # The directory structure SHOULD be:
+    # /home/username/agent
+    # |-- agent-linux
+    # |    |-- .git
+    # |    +-- ...
+    # |-- agent-win
+    # |    +-- agent-win-%(version).exe
+    #
 
 try:
-    git_env = {'GIT_DIR': join(AGENT_DIR, '.git')}
+    git_env = {'GIT_DIR': join(join(AGENT_DIR, "agent-linux"), '.git')}
     AGENT_VERSION = check_output(
         ('git', 'log', '-1', r'--pretty=format:%h', 'HEAD'), env=git_env)
 except:
diff --git a/circle/dashboard/forms.py b/circle/dashboard/forms.py
index 2e4ca73..b2a8f4a 100644
--- a/circle/dashboard/forms.py
+++ b/circle/dashboard/forms.py
@@ -18,6 +18,7 @@
 from __future__ import absolute_import
 
 from datetime import timedelta
+from urlparse import urlparse
 
 from django.contrib.auth.forms import (
     AuthenticationForm, PasswordResetForm, SetPasswordForm,
@@ -39,6 +40,7 @@ from django.contrib.auth.forms import UserCreationForm as OrgUserCreationForm
 from django.forms.widgets import TextInput, HiddenInput
 from django.template import Context
 from django.template.loader import render_to_string
+from django.utils.html import escape
 from django.utils.translation import ugettext_lazy as _
 from sizefield.widgets import FileSizeWidget
 from django.core.urlresolvers import reverse_lazy
@@ -79,6 +81,12 @@ class VmSaveForm(forms.Form):
         helper.form_tag = False
         return helper
 
+    def __init__(self, *args, **kwargs):
+        default = kwargs.pop('default', None)
+        super(VmSaveForm, self).__init__(*args, **kwargs)
+        if default:
+            self.fields['name'].initial = default
+
 
 class VmCustomizeForm(forms.Form):
     name = forms.CharField(widget=forms.TextInput(attrs={
@@ -744,6 +752,20 @@ class VmRenewForm(forms.Form):
         return helper
 
 
+class VmMigrateForm(forms.Form):
+    live_migration = forms.BooleanField(
+        required=False, initial=True, label=_("live migration"))
+
+    def __init__(self, *args, **kwargs):
+        choices = kwargs.pop('choices')
+        default = kwargs.pop('default')
+        super(VmMigrateForm, self).__init__(*args, **kwargs)
+
+        self.fields.insert(0, 'to_node', forms.ModelChoiceField(
+            queryset=choices, initial=default, required=False,
+            widget=forms.RadioSelect(), label=_("Node")))
+
+
 class VmStateChangeForm(forms.Form):
 
     interrupt = forms.BooleanField(required=False, label=_(
@@ -788,6 +810,12 @@ class VmCreateDiskForm(forms.Form):
         help_text=_('Size of disk to create in bytes or with units '
                     'like MB or GB.'))
 
+    def __init__(self, *args, **kwargs):
+        default = kwargs.pop('default', None)
+        super(VmCreateDiskForm, self).__init__(*args, **kwargs)
+        if default:
+            self.fields['name'].initial = default
+
     def clean_size(self):
         size_in_bytes = self.cleaned_data.get("size")
         if not size_in_bytes.isdigit() and len(size_in_bytes) > 0:
@@ -839,13 +867,42 @@ class VmDiskResizeForm(forms.Form):
         helper.form_tag = False
         if self.disk:
             helper.layout = Layout(
-                HTML(_("<label>Disk:</label> %s") % self.disk),
+                HTML(_("<label>Disk:</label> %s") % escape(self.disk)),
                 Field('disk'), Field('size'))
         return helper
 
 
+class VmDiskRemoveForm(forms.Form):
+    def __init__(self, *args, **kwargs):
+        choices = kwargs.pop('choices')
+        self.disk = kwargs.pop('default')
+
+        super(VmDiskRemoveForm, self).__init__(*args, **kwargs)
+
+        self.fields.insert(0, 'disk', forms.ModelChoiceField(
+            queryset=choices, initial=self.disk, required=True,
+            empty_label=None, label=_('Disk')))
+        if self.disk:
+            self.fields['disk'].widget = HiddenInput()
+
+    @property
+    def helper(self):
+        helper = FormHelper(self)
+        helper.form_tag = False
+        if self.disk:
+            helper.layout = Layout(
+                AnyTag(
+                    "div",
+                    HTML(_("<label>Disk:</label> %s") % escape(self.disk)),
+                    css_class="form-group",
+                ),
+                Field("disk"),
+            )
+        return helper
+
+
 class VmDownloadDiskForm(forms.Form):
-    name = forms.CharField(max_length=100, label=_("Name"))
+    name = forms.CharField(max_length=100, label=_("Name"), required=False)
     url = forms.CharField(label=_('URL'), validators=[URLValidator(), ])
 
     @property
@@ -854,6 +911,18 @@ class VmDownloadDiskForm(forms.Form):
         helper.form_tag = False
         return helper
 
+    def clean(self):
+        cleaned_data = super(VmDownloadDiskForm, self).clean()
+        if not cleaned_data['name']:
+            if cleaned_data['url']:
+                cleaned_data['name'] = urlparse(
+                    cleaned_data['url']).path.split('/')[-1]
+            if not cleaned_data['name']:
+                raise forms.ValidationError(
+                    _("Could not find filename in URL, "
+                      "please specify a name explicitly."))
+        return cleaned_data
+
 
 class VmAddInterfaceForm(forms.Form):
     def __init__(self, *args, **kwargs):
diff --git a/circle/dashboard/static/dashboard/dashboard.css b/circle/dashboard/static/dashboard/dashboard.css
index 8cf5ae8..c0a12ed 100644
--- a/circle/dashboard/static/dashboard/dashboard.css
+++ b/circle/dashboard/static/dashboard/dashboard.css
@@ -528,7 +528,7 @@ footer a, footer a:hover, footer a:visited {
 }
 
 #dashboard-template-list a small {
-  max-width: 50%;
+  max-width: 45%;
   float: left;
   padding-top: 2px;
   text-overflow: ellipsis;
@@ -1012,3 +1012,7 @@ textarea[name="new_members"] {
 .disk-resize-btn {
   margin-right: 5px;
 }
+
+#vm-migrate-node-list li {
+  cursor: pointer;
+}
diff --git a/circle/dashboard/static/dashboard/dashboard.js b/circle/dashboard/static/dashboard/dashboard.js
index a497d6b..3f1d22d 100644
--- a/circle/dashboard/static/dashboard/dashboard.js
+++ b/circle/dashboard/static/dashboard/dashboard.js
@@ -411,6 +411,17 @@ $(function () {
     $(this).removeClass("btn-default").addClass("btn-primary");
     return false;
   });
+
+  // vm migrate select for node
+  $(document).on("click", "#vm-migrate-node-list li", function(e) {
+    var li = $(this).closest('li');
+    if (li.find('input').attr('disabled'))
+      return true;
+    $('#vm-migrate-node-list li').removeClass('panel-primary');
+    li.addClass('panel-primary').find('input').prop("checked", true);
+    return true;
+  });
+
 });
 
 function generateVmHTML(pk, name, host, icon, _status, fav, is_last) {
@@ -445,7 +456,7 @@ function generateNodeHTML(name, icon, _status, url, is_last) {
 
 function generateNodeTagHTML(name, icon, _status, label , url) {
   return '<a href="' + url + '" class="label ' + label + '" >' +
-        '<i class="' + icon + '" title="' + _status + '"></i> ' + name +
+        '<i class="fa ' + icon + '" title="' + _status + '"></i> ' + name +
         '</a> ';
 }
 
diff --git a/circle/dashboard/static/dashboard/vm-common.js b/circle/dashboard/static/dashboard/vm-common.js
index fb4d0b6..66d6f71 100644
--- a/circle/dashboard/static/dashboard/vm-common.js
+++ b/circle/dashboard/static/dashboard/vm-common.js
@@ -16,15 +16,6 @@ $(function() {
         $('#confirmation-modal').on('hidden.bs.modal', function() {
           $('#confirmation-modal').remove();
         });
-
-        $('#vm-migrate-node-list li').click(function(e) {
-          var li = $(this).closest('li');
-          if (li.find('input').attr('disabled'))
-            return true;
-          $('#vm-migrate-node-list li').removeClass('panel-primary');
-          li.addClass('panel-primary').find('input').attr('checked', true);
-          return false;
-        });
         $('#vm-migrate-node-list li input:checked').closest('li').addClass('panel-primary');
       }
     });
@@ -51,7 +42,8 @@ $(function() {
         if(data.success) {
           $('a[href="#activity"]').trigger("click");
           if(data.with_reload) {
-            location.reload();
+            // when the activity check stops the page will reload
+            reload_vm_detail = true;
           }
 
           /* if there are messages display them */
diff --git a/circle/dashboard/static/dashboard/vm-details.js b/circle/dashboard/static/dashboard/vm-details.js
index 76865fc..dbaf4b4 100644
--- a/circle/dashboard/static/dashboard/vm-details.js
+++ b/circle/dashboard/static/dashboard/vm-details.js
@@ -1,6 +1,7 @@
 var show_all = false;
 var in_progress = false;
 var activity_hash = 5;
+var reload_vm_detail = false;
 
 $(function() {
   /* do we need to check for new activities */
@@ -404,6 +405,7 @@ function checkNewActivity(runs) {
         );
       } else {
         in_progress = false;
+        if(reload_vm_detail) location.reload();
       }
       $('a[href="#activity"] i').removeClass('fa-spin');
     },
diff --git a/circle/dashboard/templates/dashboard/_disk-list-element.html b/circle/dashboard/templates/dashboard/_disk-list-element.html
index 70f35af..23ae790 100644
--- a/circle/dashboard/templates/dashboard/_disk-list-element.html
+++ b/circle/dashboard/templates/dashboard/_disk-list-element.html
@@ -1,28 +1,29 @@
 {% load i18n %}
 {% load sizefieldtags %}
 
-<i class="fa {% if d.is_downloading %}fa-refresh fa-spin{% else %}fa-file{% if d.failed %}" style="color: #d9534f;{% endif %}{% endif %}"></i>
-{{ d.name }} (#{{ d.id }}) -
-{% if not d.is_downloading %}
-  {% if not d.failed %}
-    {% if d.size %}{{ d.size|filesize }}{% endif %}
-  {% else %}
-  <div class="label label-danger"{% if user.is_superuser %} title="{{ d.get_latest_activity_result }}"{% endif %}>{% trans "failed" %}</div>
-  {% endif %}
-{% else %}<span class="disk-list-disk-percentage" data-disk-pk="{{ d.pk }}">{{ d.get_download_percentage }}</span>%{% endif %}
-{% if is_owner != False %}
-  <a href="{% url "dashboard.views.disk-remove" pk=d.pk %}?next={{ request.path }}"
-    data-disk-pk="{{ d.pk }}" class="btn btn-xs btn-danger pull-right disk-remove"
-    {% if not long_remove %}title="{% trans "Remove" %}"{% endif %}>
-    <i class="fa fa-times"></i>{% if long_remove %} {% trans "Remove" %}{% endif %}
-  </a>
-  {% if op.resize_disk %}
-    <span class="operation-wrapper">
-      <a href="{{ op.resize_disk.get_url }}?disk={{d.pk}}" 
-        class="btn btn-xs btn-warning pull-right operation disk-resize-btn">
-        <i class="fa fa-arrows-alt"></i> {% trans "Resize" %}
-      </a>
-    </span>
-  {% endif %}
+<i class="fa fa-file"></i>
+{{ d.name }} (#{{ d.id }}) - {{ d.size|filesize }}
+
+{% if op.remove_disk %}
+  <span class="operation-wrapper">
+    <a href="{{ op.remove_disk.get_url }}?disk={{d.pk}}"
+      class="btn btn-xs btn-{{ op.remove_disk.effect}} pull-right operation disk-remove-btn
+      {% if op.resize_disk.disabled %}disabled{% endif %}">
+      <i class="fa fa-{{ op.remove_disk.icon }}"></i> {% trans "Remove" %}
+    </a>
+  </span>
+{% endif %}
+{% if op.resize_disk %}
+  <span class="operation-wrapper">
+    <a href="{{ op.resize_disk.get_url }}?disk={{d.pk}}"
+      class="btn btn-xs btn-{{ op.resize_disk.effect }} pull-right operation disk-resize-btn
+      {% if op.resize_disk.disabled %}disabled{% endif %}">
+      <i class="fa fa-{{ op.resize_disk.icon }}"></i> {% trans "Resize" %}
+    </a>
+  </span>
 {% endif %}
 <div style="clear: both;"></div>
+
+{% if request.user.is_superuser %}
+  <small>{% trans "File name" %}: {{ d.filename }}</small>
+{% endif %}
diff --git a/circle/dashboard/templates/dashboard/_vm-mass-migrate.html b/circle/dashboard/templates/dashboard/_vm-mass-migrate.html
index 6038785..bb68c06 100644
--- a/circle/dashboard/templates/dashboard/_vm-mass-migrate.html
+++ b/circle/dashboard/templates/dashboard/_vm-mass-migrate.html
@@ -1,6 +1,7 @@
 {% extends "dashboard/mass-operate.html" %}
 {% load i18n %}
 {% load sizefieldtags %}
+{% load crispy_forms_tags %}
 
 
 {% block formfields %}
@@ -11,20 +12,20 @@
         <label for="migrate-to-none">
           <strong>{% trans "Reschedule" %}</strong>
         </label>
-        <input id="migrate-to-none" type="radio" name="node" value="" style="float: right;" checked="checked">
+        <input id="migrate-to-none" type="radio" name="to_node" value="" style="float: right;" checked="checked">
         <span class="vm-migrate-node-property">
           {% trans "This option will reschedule each virtual machine to the optimal node." %}
         </span>
         <div style="clear: both;"></div>
       </div>
     </li>
-    {% for n in nodes %}
+    {% for n in form.fields.to_node.queryset.all %}
     <li class="panel panel-default mass-migrate-node">
       <div class="panel-body">
         <label for="migrate-to-{{n.pk}}">
           <strong>{{ n }}</strong>
         </label>
-        <input id="migrate-to-{{n.pk}}" type="radio" name="node" value="{{ n.pk }}" style="float: right;"/>
+        <input id="migrate-to-{{n.pk}}" type="radio" name="to_node" value="{{ n.pk }}" style="float: right;"/>
         <span class="vm-migrate-node-property">{% trans "CPU load" %}: {{ n.cpu_usage }}</span>
         <span class="vm-migrate-node-property">{% trans "RAM usage" %}: {{ n.byte_ram_usage|filesize }}/{{ n.ram_size|filesize }}</span>
         <div style="clear: both;"></div>
@@ -32,5 +33,6 @@
     </li>
     {% endfor %}
   </ul>
+  {{ form.live_migration|as_crispy_field }}
   <hr />
 {% endblock %}
diff --git a/circle/dashboard/templates/dashboard/_vm-migrate.html b/circle/dashboard/templates/dashboard/_vm-migrate.html
index 205228a..c8024c4 100644
--- a/circle/dashboard/templates/dashboard/_vm-migrate.html
+++ b/circle/dashboard/templates/dashboard/_vm-migrate.html
@@ -1,6 +1,7 @@
 {% extends "dashboard/operate.html" %}
 {% load i18n %}
 {% load sizefieldtags %}
+{% load crispy_forms_tags %}
 
 {% block question %}
 <p>
@@ -13,24 +14,27 @@ Choose a compute node to migrate {{obj}} to.
 
 {% block formfields %}
   <ul id="vm-migrate-node-list" class="list-unstyled">
-  {% with current=object.node.pk %}
-    {% for n in nodes %}
+  {% with current=object.node.pk recommended=form.fields.to_node.initial.pk %}
+    {% for n in form.fields.to_node.queryset.all %}
       <li class="panel panel-default"><div class="panel-body">
         <label for="migrate-to-{{n.pk}}">
           <strong>{{ n }}</strong>
-          <div class="label label-primary"><i class="fa {{n.get_status_icon}}"></i>
-              {{n.get_status_display}}</div>
+          <div class="label label-primary">
+            <i class="fa {{n.get_status_icon}}"></i> {{n.get_status_display}}</div>
           {% if current == n.pk %}<div class="label label-info">{% trans "current" %}</div>{% endif %}
           {% if recommended == n.pk %}<div class="label label-success">{% trans "recommended" %}</div>{% endif %}
         </label>
-        <input id="migrate-to-{{n.pk}}" type="radio" name="node" value="{{ n.pk }}" style="float: right;"
-        {% if current == n.pk %}disabled="disabled"{% endif %}
-        {% if recommended == n.pk %}checked="checked"{% endif %} />
+        <input id="migrate-to-{{n.pk}}" type="radio" name="to_node" value="{{ n.pk }}" style="float: right;"
+          {% if current == n.pk %}disabled="disabled"{% endif %}
+          {% if recommended == n.pk %}checked="checked"{% endif %}
+        />
         <span class="vm-migrate-node-property">{% trans "CPU load" %}: {{ n.cpu_usage }}</span>
-        <span class="vm-migrate-node-property">{% trans "RAM usage" %}: {{ n.byte_ram_usage|filesize }}/{{ n.ram_size|filesize }}</span>
+        <span class="vm-migrate-node-property">
+          {% trans "RAM usage" %}: {{ n.byte_ram_usage|filesize }}/{{ n.ram_size|filesize }}</span>
         <div style="clear: both;"></div>
-      </div></li>
+      </li>
     {% endfor %}
   {% endwith %}
   </ul>
+  {{ form.live_migration|as_crispy_field }}
 {% endblock %}
diff --git a/circle/dashboard/templates/dashboard/index-nodes.html b/circle/dashboard/templates/dashboard/index-nodes.html
index e6ecb49..0ff215c 100644
--- a/circle/dashboard/templates/dashboard/index-nodes.html
+++ b/circle/dashboard/templates/dashboard/index-nodes.html
@@ -1,5 +1,5 @@
 {% load i18n %}
-  <div class="panel panel-default">
+<div class="panel panel-default">
   <div class="panel-heading">
     <div class="pull-right toolbar">
       <div class="btn-group">
@@ -7,9 +7,10 @@
           data-container="body"><i class="fa fa-dashboard"></i></a>
         <a href="#index-list-view" data-index-box="node" class="btn btn-default btn-xs disabled"
           data-container="body"><i class="fa fa-list"></i></a>
-
       </div>
-      <span class="btn btn-default btn-xs infobtn" title="{% trans "List of compute nodes, also called worker nodes or hypervisors, which run the virtual machines." %}"><i class="fa fa-info-circle"></i></span>
+      <span class="btn btn-default btn-xs infobtn" title="{% trans "List of compute nodes, also called worker nodes or hypervisors, which run the virtual machines." %}">
+        <i class="fa fa-info-circle"></i>
+      </span>
     </div>
     <h3 class="no-margin">
       <i class="fa fa-sitemap"></i> {% trans "Nodes" %}
@@ -28,50 +29,55 @@
       </a>
       {% endfor %}
     </div>
-    <div href="#" class="list-group-item list-group-footer">
-      <div class="row">
-        <div class="col-sm-6 col-xs-6 input-group input-group-sm">
-          <input id="dashboard-node-search-input" type="text" class="form-control" placeholder="{% trans "Search..." %}" />
-          <div class="input-group-btn">
-            <button type="submit" class="form-control btn btn-primary" title="search"><i class="fa fa-search"></i></button>
-          </div>
-        </div>
-        <div class="col-sm-6 text-right">
-          <a class="btn btn-primary btn-xs" href="{% url "dashboard.views.node-list" %}">
-            <i class="fa fa-chevron-circle-right"></i>
-            {% if more_nodes > 0 %}
-                {% blocktrans with count=more_nodes %}<strong>{{count}}</strong>  more{% endblocktrans %}
-            {% else %}
-                {% trans "list" %}
-            {% endif %}
-          </a>
-          <a class="btn btn-success btn-xs node-create" href="{% url "dashboard.views.node-create" %}"><i class="fa fa-plus-circle"></i> {% trans "new" %}</a>
-        </div>
-      </div>
-    </div>
-  </div>
+  </div><!-- #node-list-view -->
 
-  <div class="panel-body" id="node-graph-view" style="display: none">
-    <p class="pull-right">  <input class="knob" data-fgColor="chartreuse" data-thickness=".4" data-width="60" data-height="60" data-readOnly="true" value="{% widthratio node_num.running sum_node_num 100 %}"></p>
-    <p><span class="big"><big>{{ node_num.running }}</big> running </span>
-    + <big>{{ node_num.missing }}</big> missing + <br><big>{{ node_num.disabled }}</big> disabled + <big>{{ node_num.offline }}</big> offline</p>
-      <ul class="list-inline" id="dashboard-node-taglist">
-        {% for i in nodes %}
-        <a href="{{ i.get_absolute_url }}" class="label {{i.get_status_label}}" >
-        <i class="fa {{ i.get_status_icon }}" title="{{ i.get_status_display }}"></i> {{ i.name }}</a>
-        {% endfor %}
-      </ul>
+  <div class="panel-body" id="node-graph-view" style="display: none; min-height: 204px;">
+    <p class="pull-right">
+      <input class="knob" data-fgColor="chartreuse"
+      data-thickness=".4" data-width="60" data-height="60" data-readOnly="true"
+      value="{% widthratio node_num.running sum_node_num 100 %}">
+    </p>
+    <p>
+      <span class="big">
+        <big>{{ node_num.running }}</big> running
+      </span>
+      + <big>{{ node_num.missing }}</big>
+      missing + <br><big>{{ node_num.disabled }}</big> disabled + <big>{{ node_num.offline }}</big> offline
+    </p>
+    <ul class="list-inline" id="dashboard-node-taglist">
+      {% for i in nodes %}
+      <a href="{{ i.get_absolute_url }}" class="label {{i.get_status_label}}" >
+      <i class="fa {{ i.get_status_icon }}" title="{{ i.get_status_display }}"></i> {{ i.name }}</a>
+      {% endfor %}
+    </ul>
 
     <div class="clearfix"></div>
- <div class="row">
-        <div class="col-sm-6 text-right pull-right">
-         {% if more_nodes >= 0  %}
-          <a class="btn btn-primary btn-xs" href="{% url "dashboard.views.node-list" %}">
-            <i class="fa fa-chevron-circle-right"></i> {% blocktrans with count=more_nodes %}<strong>{{count}}</strong>  more{% endblocktrans %}
-          </a>
-         {% endif %}
-         <a class="btn btn-success btn-xs node-create" href="{% url "dashboard.views.node-create" %}"><i class="fa fa-plus-circle"></i> {% trans "new" %}</a>
+  </div>
+
+  <div href="#" class="list-group-item list-group-footer">
+    <div class="row">
+      <div class="col-sm-6 col-xs-6 input-group input-group-sm">
+        <input id="dashboard-node-search-input" type="text" class="form-control"
+         placeholder="{% trans "Search..." %}" />
+        <div class="input-group-btn">
+          <button type="submit" class="btn btn-primary" title="{% trans "Search" %}" data-container="body">
+            <i class="fa fa-search"></i>
+          </button>
         </div>
-</div>
-</div>
+      </div>
+      <div class="col-sm-6 text-right">
+        <a class="btn btn-primary btn-xs" href="{% url "dashboard.views.node-list" %}">
+          <i class="fa fa-chevron-circle-right"></i>
+          {% if more_nodes > 0 %}
+              {% blocktrans with count=more_nodes %}<strong>{{count}}</strong>  more{% endblocktrans %}
+          {% else %}
+              {% trans "list" %}
+          {% endif %}
+        </a>
+        <a class="btn btn-success btn-xs node-create" href="{% url "dashboard.views.node-create" %}">
+          <i class="fa fa-plus-circle"></i> {% trans "new" %}
+        </a>
+      </div>
+    </div>
+  </div>
 </div>
diff --git a/circle/dashboard/templates/dashboard/instanceactivity_detail.html b/circle/dashboard/templates/dashboard/instanceactivity_detail.html
index adeed94..3733550 100644
--- a/circle/dashboard/templates/dashboard/instanceactivity_detail.html
+++ b/circle/dashboard/templates/dashboard/instanceactivity_detail.html
@@ -58,6 +58,26 @@
 
             <dt>{% trans "resultant state" %}</dt>
             <dd>{{object.resultant_state|default:'n/a'}}</dd>
+
+            <dt>{% trans "subactivities" %}</dt>
+            {% for s in object.children.all %}
+              <dd>
+                <span{% if s.result %} title="{{ s.result|get_text:user }}"{% endif %}>
+                  <a href="{{ s.get_absolute_url }}">
+                      {{ s.readable_name|get_text:user|capfirst }}</a></span> &ndash;
+                {% if s.finished %}
+                  {{ s.finished|time:"H:i:s" }}
+                {% else %}
+                  <i class="fa fa-refresh fa-spin" class="sub-activity-loading-icon"></i>
+                {% endif %}
+                {% if s.has_failed %}
+                  <div class="label label-danger">{% trans "failed" %}</div>
+                {% endif %}
+              </dd>
+            {% empty %}
+              <dd>{% trans "none" %}</dd>
+            {% endfor %}
+          </div>
         </div>
       </div>
     </div>
diff --git a/circle/dashboard/templates/dashboard/node-list/column-vm.html b/circle/dashboard/templates/dashboard/node-list/column-vm.html
index e12ecd4..c8d6b0c 100644
--- a/circle/dashboard/templates/dashboard/node-list/column-vm.html
+++ b/circle/dashboard/templates/dashboard/node-list/column-vm.html
@@ -1,7 +1,7 @@
 {% load i18n %}
 
 <div id="node-list-column-vm">
-  <a class="real-link" href="{% url "dashboard.views.vm-list" %}?s=node:{{ record.name }}">
+  <a class="real-link" href="{% url "dashboard.views.vm-list" %}?s=node_exact:{{ record.name }}">
     {{ value }}
   </a>
 </div>
diff --git a/circle/dashboard/templates/dashboard/template-edit.html b/circle/dashboard/templates/dashboard/template-edit.html
index ba9a442..d6bc6b5 100644
--- a/circle/dashboard/templates/dashboard/template-edit.html
+++ b/circle/dashboard/templates/dashboard/template-edit.html
@@ -86,7 +86,13 @@
         {% endif %}
         {% for d in disks %}
           <li>
-            {% include "dashboard/_disk-list-element.html" %}
+            <i class="fa fa-file"></i>
+            {{ d.name }} (#{{ d.id }}) -
+            <a href="{% url "dashboard.views.disk-remove" pk=d.pk %}?next={{ request.path }}"
+              data-disk-pk="{{ d.pk }}" class="btn btn-xs btn-danger pull-right disk-remove"
+              {% if not long_remove %}title="{% trans "Remove" %}"{% endif %}>
+              <i class="fa fa-times"></i>{% if long_remove %} {% trans "Remove" %}{% endif %}
+            </a>
           </li>
         {% endfor %}
         </ul>
diff --git a/circle/dashboard/tests/test_mockedviews.py b/circle/dashboard/tests/test_mockedviews.py
index 4a28660..7d22bd4 100644
--- a/circle/dashboard/tests/test_mockedviews.py
+++ b/circle/dashboard/tests/test_mockedviews.py
@@ -34,6 +34,13 @@ from ..views import AclUpdateView
 from .. import views
 
 
+class QuerySet(list):
+    model = MagicMock()
+
+    def get(self, *args, **kwargs):
+        return self.pop()
+
+
 class ViewUserTestCase(unittest.TestCase):
 
     def test_404(self):
@@ -145,58 +152,66 @@ class VmOperationViewTestCase(unittest.TestCase):
                 view.as_view()(request, pk=1234).render()
 
     def test_migrate(self):
-        request = FakeRequestFactory(POST={'node': 1}, superuser=True)
+        request = FakeRequestFactory(
+            POST={'to_node': 1, 'live_migration': True}, superuser=True)
         view = vm_ops['migrate']
+        node = MagicMock(pk=1, name='node1')
 
         with patch.object(view, 'get_object') as go, \
                 patch('dashboard.views.util.messages') as msg, \
-                patch('dashboard.views.vm.get_object_or_404') as go4:
+                patch.object(view, 'get_form_kwargs') as form_kwargs:
             inst = MagicMock(spec=Instance)
             inst._meta.object_name = "Instance"
             inst.migrate = Instance._ops['migrate'](inst)
             inst.migrate.async = MagicMock()
             inst.has_level.return_value = True
+            form_kwargs.return_value = {
+                'default': 100, 'choices': QuerySet([node])}
             go.return_value = inst
-            go4.return_value = MagicMock()
             assert view.as_view()(request, pk=1234)['location']
             assert not msg.error.called
-            assert go4.called
+            inst.migrate.async.assert_called_once_with(
+                to_node=node, live_migration=True, user=request.user)
 
     def test_migrate_failed(self):
-        request = FakeRequestFactory(POST={'node': 1}, superuser=True)
+        request = FakeRequestFactory(POST={'to_node': 1}, superuser=True)
         view = vm_ops['migrate']
+        node = MagicMock(pk=1, name='node1')
 
         with patch.object(view, 'get_object') as go, \
                 patch('dashboard.views.util.messages') as msg, \
-                patch('dashboard.views.vm.get_object_or_404') as go4:
+                patch.object(view, 'get_form_kwargs') as form_kwargs:
             inst = MagicMock(spec=Instance)
             inst._meta.object_name = "Instance"
             inst.migrate = Instance._ops['migrate'](inst)
             inst.migrate.async = MagicMock()
             inst.migrate.async.side_effect = Exception
             inst.has_level.return_value = True
+            form_kwargs.return_value = {
+                'default': 100, 'choices': QuerySet([node])}
             go.return_value = inst
-            go4.return_value = MagicMock()
             assert view.as_view()(request, pk=1234)['location']
+            assert inst.migrate.async.called
             assert msg.error.called
-            assert go4.called
 
     def test_migrate_wo_permission(self):
-        request = FakeRequestFactory(POST={'node': 1}, superuser=False)
+        request = FakeRequestFactory(POST={'to_node': 1}, superuser=False)
         view = vm_ops['migrate']
+        node = MagicMock(pk=1, name='node1')
 
         with patch.object(view, 'get_object') as go, \
-                patch('dashboard.views.vm.get_object_or_404') as go4:
+                patch.object(view, 'get_form_kwargs') as form_kwargs:
             inst = MagicMock(spec=Instance)
             inst._meta.object_name = "Instance"
             inst.migrate = Instance._ops['migrate'](inst)
             inst.migrate.async = MagicMock()
             inst.has_level.return_value = True
+            form_kwargs.return_value = {
+                'default': 100, 'choices': QuerySet([node])}
             go.return_value = inst
-            go4.return_value = MagicMock()
             with self.assertRaises(PermissionDenied):
                 assert view.as_view()(request, pk=1234)['location']
-            assert go4.called
+            assert not inst.migrate.async.called
 
     def test_migrate_template(self):
         """check if GET dialog's template can be rendered"""
@@ -219,6 +234,7 @@ class VmOperationViewTestCase(unittest.TestCase):
         with patch.object(view, 'get_object') as go, \
                 patch('dashboard.views.util.messages') as msg:
             inst = MagicMock(spec=Instance)
+            inst.name = "asd"
             inst._meta.object_name = "Instance"
             inst.save_as_template = Instance._ops['save_as_template'](inst)
             inst.save_as_template.async = MagicMock()
@@ -235,6 +251,7 @@ class VmOperationViewTestCase(unittest.TestCase):
         with patch.object(view, 'get_object') as go, \
                 patch('dashboard.views.util.messages') as msg:
             inst = MagicMock(spec=Instance)
+            inst.name = "asd"
             inst._meta.object_name = "Instance"
             inst.save_as_template = Instance._ops['save_as_template'](inst)
             inst.save_as_template.async = MagicMock()
@@ -301,7 +318,7 @@ class VmMassOperationViewTestCase(unittest.TestCase):
                 view.as_view()(request, pk=1234).render()
 
     def test_migrate(self):
-        request = FakeRequestFactory(POST={'node': 1}, superuser=True)
+        request = FakeRequestFactory(POST={'to_node': 1}, superuser=True)
         view = vm_mass_ops['migrate']
 
         with patch.object(view, 'get_object') as go, \
@@ -318,7 +335,7 @@ class VmMassOperationViewTestCase(unittest.TestCase):
             assert not msg2.error.called
 
     def test_migrate_failed(self):
-        request = FakeRequestFactory(POST={'node': 1}, superuser=True)
+        request = FakeRequestFactory(POST={'to_node': 1}, superuser=True)
         view = vm_mass_ops['migrate']
 
         with patch.object(view, 'get_object') as go, \
@@ -334,7 +351,7 @@ class VmMassOperationViewTestCase(unittest.TestCase):
             assert msg.error.called
 
     def test_migrate_wo_permission(self):
-        request = FakeRequestFactory(POST={'node': 1}, superuser=False)
+        request = FakeRequestFactory(POST={'to_node': 1}, superuser=False)
         view = vm_mass_ops['migrate']
 
         with patch.object(view, 'get_object') as go:
diff --git a/circle/dashboard/views/template.py b/circle/dashboard/views/template.py
index aac295b..d5fd13b 100644
--- a/circle/dashboard/views/template.py
+++ b/circle/dashboard/views/template.py
@@ -37,6 +37,7 @@ from braces.views import (
 from django_tables2 import SingleTableView
 
 from vm.models import InstanceTemplate, InterfaceTemplate, Instance, Lease
+from storage.models import Disk
 
 from ..forms import (
     TemplateForm, TemplateListSearchForm, AclUserOrGroupAddForm, LeaseForm,
@@ -319,6 +320,57 @@ class TemplateDetail(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
         return kwargs
 
 
+class DiskRemoveView(DeleteView):
+    model = Disk
+
+    def get_queryset(self):
+        qs = super(DiskRemoveView, self).get_queryset()
+        return qs.exclude(template_set=None)
+
+    def get_template_names(self):
+        if self.request.is_ajax():
+            return ['dashboard/confirm/ajax-delete.html']
+        else:
+            return ['dashboard/confirm/base-delete.html']
+
+    def get_context_data(self, **kwargs):
+        context = super(DiskRemoveView, self).get_context_data(**kwargs)
+        disk = self.get_object()
+        template = disk.template_set.get()
+        if not template.has_level(self.request.user, 'owner'):
+            raise PermissionDenied()
+        context['title'] = _("Disk remove confirmation")
+        context['text'] = _("Are you sure you want to remove "
+                            "<strong>%(disk)s</strong> from "
+                            "<strong>%(app)s</strong>?" % {'disk': disk,
+                                                           'app': template}
+                            )
+        return context
+
+    def delete(self, request, *args, **kwargs):
+        disk = self.get_object()
+        template = disk.template_set.get()
+
+        if not template.has_level(request.user, 'owner'):
+            raise PermissionDenied()
+
+        template.remove_disk(disk=disk, user=request.user)
+        disk.destroy()
+
+        next_url = request.POST.get("next")
+        success_url = next_url if next_url else template.get_absolute_url()
+        success_message = _("Disk successfully removed.")
+
+        if request.is_ajax():
+            return HttpResponse(
+                json.dumps({'message': success_message}),
+                content_type="application/json",
+            )
+        else:
+            messages.success(request, success_message)
+            return HttpResponseRedirect("%s#resources" % success_url)
+
+
 class LeaseCreate(LoginRequiredMixin, PermissionRequiredMixin,
                   SuccessMessageMixin, CreateView):
     model = Lease
diff --git a/circle/dashboard/views/vm.py b/circle/dashboard/views/vm.py
index c07d11e..38f3dfe 100644
--- a/circle/dashboard/views/vm.py
+++ b/circle/dashboard/views/vm.py
@@ -59,7 +59,8 @@ from ..forms import (
     AclUserOrGroupAddForm, VmResourcesForm, TraitsForm, RawDataForm,
     VmAddInterfaceForm, VmCreateDiskForm, VmDownloadDiskForm, VmSaveForm,
     VmRenewForm, VmStateChangeForm, VmListSearchForm, VmCustomizeForm,
-    TransferOwnershipForm, VmDiskResizeForm, RedeployForm,
+    TransferOwnershipForm, VmDiskResizeForm, RedeployForm, VmDiskRemoveForm,
+    VmMigrateForm,
 )
 from ..models import Favourite, Profile
 
@@ -370,11 +371,9 @@ class VmAddInterfaceView(FormOperationMixin, VmOperationView):
         return val
 
 
-class VmDiskResizeView(FormOperationMixin, VmOperationView):
-
-    op = 'resize_disk'
-    form_class = VmDiskResizeForm
+class VmDiskModifyView(FormOperationMixin, VmOperationView):
     show_in_toolbar = False
+    with_reload = True
     icon = 'arrows-alt'
     effect = "success"
 
@@ -389,7 +388,7 @@ class VmDiskResizeView(FormOperationMixin, VmOperationView):
         else:
             default = None
 
-        val = super(VmDiskResizeView, self).get_form_kwargs()
+        val = super(VmDiskModifyView, self).get_form_kwargs()
         val.update({'choices': choices, 'default': default})
         return val
 
@@ -402,6 +401,14 @@ class VmCreateDiskView(FormOperationMixin, VmOperationView):
     icon = 'hdd-o'
     effect = "success"
     is_disk_operation = True
+    with_reload = True
+
+    def get_form_kwargs(self):
+        op = self.get_op()
+        val = super(VmCreateDiskView, self).get_form_kwargs()
+        num = op.instance.disks.count() + 1
+        val['default'] = "%s %d" % (op.instance.name, num)
+        return val
 
 
 class VmDownloadDiskView(FormOperationMixin, VmOperationView):
@@ -412,38 +419,31 @@ class VmDownloadDiskView(FormOperationMixin, VmOperationView):
     icon = 'download'
     effect = "success"
     is_disk_operation = True
+    with_reload = True
 
 
-class VmMigrateView(VmOperationView):
+class VmMigrateView(FormOperationMixin, VmOperationView):
 
     op = 'migrate'
     icon = 'truck'
     effect = 'info'
     template_name = 'dashboard/_vm-migrate.html'
+    form_class = VmMigrateForm
 
-    def get_context_data(self, **kwargs):
-        ctx = super(VmMigrateView, self).get_context_data(**kwargs)
-        ctx['nodes'] = [n for n in Node.objects.filter(enabled=True)
-                        if n.online]
-
+    def get_form_kwargs(self):
+        online = (n.pk for n in Node.objects.filter(enabled=True) if n.online)
+        choices = Node.objects.filter(pk__in=online)
+        default = None
         inst = self.get_object()
-        ctx["recommended"] = None
         try:
             if isinstance(inst, Instance):
-                ctx["recommended"] = inst.select_node().pk
+                default = inst.select_node()
         except SchedulerError:
             logger.exception("scheduler error:")
 
-        return ctx
-
-    def post(self, request, extra=None, *args, **kwargs):
-        if extra is None:
-            extra = {}
-        node = self.request.POST.get("node")
-        if node:
-            node = get_object_or_404(Node, pk=node)
-            extra["to_node"] = node
-        return super(VmMigrateView, self).post(request, extra, *args, **kwargs)
+        val = super(VmMigrateView, self).get_form_kwargs()
+        val.update({'choices': choices, 'default': default})
+        return val
 
 
 class VmSaveView(FormOperationMixin, VmOperationView):
@@ -453,6 +453,12 @@ class VmSaveView(FormOperationMixin, VmOperationView):
     effect = 'info'
     form_class = VmSaveForm
 
+    def get_form_kwargs(self):
+        op = self.get_op()
+        val = super(VmSaveView, self).get_form_kwargs()
+        val['default'] = op._rename(op.instance.name)
+        return val
+
 
 class VmResourcesChangeView(VmOperationView):
     op = 'resources_change'
@@ -649,7 +655,12 @@ vm_ops = OrderedDict([
         op='destroy', icon='times', effect='danger')),
     ('create_disk', VmCreateDiskView),
     ('download_disk', VmDownloadDiskView),
-    ('resize_disk', VmDiskResizeView),
+    ('resize_disk', VmDiskModifyView.factory(
+        op='resize_disk', form_class=VmDiskResizeForm,
+        icon='arrows-alt', effect="warning")),
+    ('remove_disk', VmDiskModifyView.factory(
+        op='remove_disk', form_class=VmDiskRemoveForm,
+        icon='times', effect="danger")),
     ('add_interface', VmAddInterfaceView),
     ('renew', VmRenewView),
     ('resources_change', VmResourcesChangeView),
@@ -751,6 +762,12 @@ class MassOperationView(OperationView):
         self.check_auth()
         if extra is None:
             extra = {}
+
+        if hasattr(self, 'form_class'):
+            form = self.form_class(self.request.POST, **self.get_form_kwargs())
+            if form.is_valid():
+                extra.update(form.cleaned_data)
+
         self._call_operations(extra)
         if request.is_ajax():
             store = messages.get_messages(request)
@@ -789,6 +806,7 @@ class VmList(LoginRequiredMixin, FilterMixin, ListView):
     allowed_filters = {
         'name': "name__icontains",
         'node': "node__name__icontains",
+        'node_exact': "node__name",
         'status': "status__iexact",
         'tags[]': "tags__name__in",
         'tags': "tags__name__in",  # for search string
@@ -1112,51 +1130,6 @@ class InstanceActivityDetail(CheckedDetailView):
         return ctx
 
 
-class DiskRemoveView(DeleteView):
-    model = Disk
-
-    def get_template_names(self):
-        if self.request.is_ajax():
-            return ['dashboard/confirm/ajax-delete.html']
-        else:
-            return ['dashboard/confirm/base-delete.html']
-
-    def get_context_data(self, **kwargs):
-        context = super(DiskRemoveView, self).get_context_data(**kwargs)
-        disk = self.get_object()
-        app = disk.get_appliance()
-        context['title'] = _("Disk remove confirmation")
-        context['text'] = _("Are you sure you want to remove "
-                            "<strong>%(disk)s</strong> from "
-                            "<strong>%(app)s</strong>?" % {'disk': disk,
-                                                           'app': app}
-                            )
-        return context
-
-    def delete(self, request, *args, **kwargs):
-        disk = self.get_object()
-        app = disk.get_appliance()
-
-        if not app.has_level(request.user, 'owner'):
-            raise PermissionDenied()
-
-        app.remove_disk(disk=disk, user=request.user)
-        disk.destroy()
-
-        next_url = request.POST.get("next")
-        success_url = next_url if next_url else app.get_absolute_url()
-        success_message = _("Disk successfully removed.")
-
-        if request.is_ajax():
-            return HttpResponse(
-                json.dumps({'message': success_message}),
-                content_type="application/json",
-            )
-        else:
-            messages.success(request, success_message)
-            return HttpResponseRedirect("%s#resources" % success_url)
-
-
 @require_GET
 def get_disk_download_status(request, pk):
     disk = Disk.objects.get(pk=pk)
diff --git a/circle/firewall/migrations/0052_auto__chg_field_record_address.py b/circle/firewall/migrations/0052_auto__chg_field_record_address.py
new file mode 100644
index 0000000..e911ec8
--- /dev/null
+++ b/circle/firewall/migrations/0052_auto__chg_field_record_address.py
@@ -0,0 +1,201 @@
+# -*- coding: utf-8 -*-
+from south.utils import datetime_utils as datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+
+        # Changing field 'Record.address'
+        db.alter_column(u'firewall_record', 'address', self.gf('django.db.models.fields.CharField')(max_length=400))
+
+    def backwards(self, orm):
+
+        # Changing field 'Record.address'
+        db.alter_column(u'firewall_record', 'address', self.gf('django.db.models.fields.CharField')(max_length=200))
+
+    models = {
+        u'auth.group': {
+            'Meta': {'object_name': 'Group'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+        },
+        u'auth.permission': {
+            'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
+            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        u'auth.user': {
+            'Meta': {'object_name': 'User'},
+            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
+            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+        },
+        u'contenttypes.contenttype': {
+            'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        u'firewall.blacklistitem': {
+            'Meta': {'object_name': 'BlacklistItem'},
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'host': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['firewall.Host']", 'null': 'True', 'blank': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'ipv4': ('django.db.models.fields.GenericIPAddressField', [], {'unique': 'True', 'max_length': '39'}),
+            'modified_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'reason': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'snort_message': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'type': ('django.db.models.fields.CharField', [], {'default': "'tempban'", 'max_length': '10'})
+        },
+        u'firewall.domain': {
+            'Meta': {'object_name': 'Domain'},
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'modified_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+            'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
+            'ttl': ('django.db.models.fields.IntegerField', [], {'default': '600'})
+        },
+        u'firewall.ethernetdevice': {
+            'Meta': {'object_name': 'EthernetDevice'},
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'modified_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '20'}),
+            'switch_port': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'ethernet_devices'", 'to': u"orm['firewall.SwitchPort']"})
+        },
+        u'firewall.firewall': {
+            'Meta': {'object_name': 'Firewall'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '20'})
+        },
+        u'firewall.group': {
+            'Meta': {'object_name': 'Group'},
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'modified_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '20'}),
+            'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'})
+        },
+        u'firewall.host': {
+            'Meta': {'ordering': "('normalized_hostname', 'vlan')", 'unique_together': "(('hostname', 'vlan'),)", 'object_name': 'Host'},
+            'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'external_ipv4': ('firewall.fields.IPAddressField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['firewall.Group']", 'null': 'True', 'blank': 'True'}),
+            'hostname': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'ipv4': ('firewall.fields.IPAddressField', [], {'unique': 'True', 'max_length': '100'}),
+            'ipv6': ('firewall.fields.IPAddressField', [], {'max_length': '100', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+            'location': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'mac': ('firewall.fields.MACAddressField', [], {'unique': 'True', 'max_length': '17'}),
+            'modified_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'normalized_hostname': ('common.models.HumanSortField', [], {'default': "''", 'maximum_number_length': '4', 'max_length': '80', 'monitor': "'hostname'", 'blank': 'True'}),
+            'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
+            'reverse': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+            'shared_ip': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'vlan': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['firewall.Vlan']"})
+        },
+        u'firewall.record': {
+            'Meta': {'ordering': "('domain', 'name')", 'object_name': 'Record'},
+            'address': ('django.db.models.fields.CharField', [], {'max_length': '400'}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'domain': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['firewall.Domain']"}),
+            'host': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['firewall.Host']", 'null': 'True', 'blank': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'modified_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+            'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
+            'ttl': ('django.db.models.fields.IntegerField', [], {'default': '600'}),
+            'type': ('django.db.models.fields.CharField', [], {'max_length': '6'})
+        },
+        u'firewall.rule': {
+            'Meta': {'ordering': "('direction', 'proto', 'sport', 'dport', 'nat_external_port', 'host')", 'object_name': 'Rule'},
+            'action': ('django.db.models.fields.CharField', [], {'default': "'drop'", 'max_length': '10'}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'direction': ('django.db.models.fields.CharField', [], {'max_length': '3'}),
+            'dport': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'extra': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'firewall': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'rules'", 'null': 'True', 'to': u"orm['firewall.Firewall']"}),
+            'foreign_network': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'ForeignRules'", 'to': u"orm['firewall.VlanGroup']"}),
+            'host': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'rules'", 'null': 'True', 'to': u"orm['firewall.Host']"}),
+            'hostgroup': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'rules'", 'null': 'True', 'to': u"orm['firewall.Group']"}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'modified_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'nat': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'nat_external_ipv4': ('firewall.fields.IPAddressField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+            'nat_external_port': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+            'proto': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
+            'sport': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'vlan': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'rules'", 'null': 'True', 'to': u"orm['firewall.Vlan']"}),
+            'vlangroup': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'rules'", 'null': 'True', 'to': u"orm['firewall.VlanGroup']"}),
+            'weight': ('django.db.models.fields.IntegerField', [], {'default': '30000'})
+        },
+        u'firewall.switchport': {
+            'Meta': {'object_name': 'SwitchPort'},
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'modified_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'tagged_vlans': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'tagged_ports'", 'null': 'True', 'to': u"orm['firewall.VlanGroup']"}),
+            'untagged_vlan': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'untagged_ports'", 'to': u"orm['firewall.Vlan']"})
+        },
+        u'firewall.vlan': {
+            'Meta': {'object_name': 'Vlan'},
+            'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'dhcp_pool': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'domain': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['firewall.Domain']"}),
+            'host_ipv6_prefixlen': ('django.db.models.fields.IntegerField', [], {'default': '112'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'ipv6_template': ('django.db.models.fields.TextField', [], {'default': "'2001:738:2001:4031:%(b)d:%(c)d:%(d)d:0'"}),
+            'managed': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+            'modified_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '20'}),
+            'network4': ('firewall.fields.IPNetworkField', [], {'max_length': '100'}),
+            'network6': ('firewall.fields.IPNetworkField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+            'network_type': ('django.db.models.fields.CharField', [], {'default': "'portforward'", 'max_length': '20'}),
+            'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+            'reverse_domain': ('django.db.models.fields.TextField', [], {'default': "'%(d)d.%(c)d.%(b)d.%(a)d.in-addr.arpa'"}),
+            'snat_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39', 'null': 'True', 'blank': 'True'}),
+            'snat_to': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['firewall.Vlan']", 'null': 'True', 'blank': 'True'}),
+            'vid': ('django.db.models.fields.IntegerField', [], {'unique': 'True'})
+        },
+        u'firewall.vlangroup': {
+            'Meta': {'object_name': 'VlanGroup'},
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'modified_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '20'}),
+            'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+            'vlans': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['firewall.Vlan']", 'null': 'True', 'blank': 'True'})
+        }
+    }
+
+    complete_apps = ['firewall']
\ No newline at end of file
diff --git a/circle/firewall/models.py b/circle/firewall/models.py
index 882ba3f..cfa4a99 100644
--- a/circle/firewall/models.py
+++ b/circle/firewall/models.py
@@ -874,7 +874,7 @@ class Record(models.Model):
                              verbose_name=_('host'))
     type = models.CharField(max_length=6, choices=CHOICES_type,
                             verbose_name=_('type'))
-    address = models.CharField(max_length=200,
+    address = models.CharField(max_length=400,
                                verbose_name=_('address'))
     ttl = models.IntegerField(default=600, verbose_name=_('ttl'))
     owner = models.ForeignKey(User, verbose_name=_('owner'))
diff --git a/circle/firewall/tasks/local_tasks.py b/circle/firewall/tasks/local_tasks.py
index 3085aca..5731a82 100644
--- a/circle/firewall/tasks/local_tasks.py
+++ b/circle/firewall/tasks/local_tasks.py
@@ -29,26 +29,24 @@ settings = django.conf.settings.FIREWALL_SETTINGS
 logger = getLogger(__name__)
 
 
-def _apply_once(name, queues, task, data):
+def _apply_once(name, tasks, queues, task, data):
     """Reload given networking component if needed.
     """
 
-    lockname = "%s_lock" % name
-    if not cache.get(lockname):
+    if name not in tasks:
         return
-    cache.delete(lockname)
 
     data = data()
     for queue in queues:
         try:
-            task.apply_async(args=data, queue=queue, expires=60).get(timeout=5)
+            task.apply_async(args=data, queue=queue, expires=60).get(timeout=2)
             logger.info("%s configuration is reloaded. (queue: %s)",
                         name, queue)
         except TimeoutError as e:
-            logger.critical('%s (queue: %s)', e, queue)
+            logger.critical('%s (queue: %s, task: %s)', e, queue, name)
         except:
-            logger.critical('Unhandled exception: queue: %s data: %s',
-                            queue, data, exc_info=True)
+            logger.critical('Unhandled exception: queue: %s data: %s task: %s',
+                            queue, data, name, exc_info=True)
 
 
 def get_firewall_queues():
@@ -68,19 +66,28 @@ def reloadtask_worker():
     from remote_tasks import (reload_dns, reload_dhcp, reload_firewall,
                               reload_firewall_vlan, reload_blacklist)
 
+    tasks = []
+    for i in ('dns', 'dhcp', 'firewall', 'firewall_vlan', 'blacklist'):
+        lockname = "%s_lock" % i
+        if cache.get(lockname):
+            tasks.append(i)
+        cache.delete(lockname)
+
+    logger.info("reloadtask_worker: Reload %s", ", ".join(tasks))
+
     firewall_queues = get_firewall_queues()
     dns_queues = [("%s.dns" % i) for i in
                   settings.get('dns_queues', [gethostname()])]
 
-    _apply_once('dns', dns_queues, reload_dns,
+    _apply_once('dns', tasks, dns_queues, reload_dns,
                 lambda: (dns(), ))
-    _apply_once('dhcp', firewall_queues, reload_dhcp,
+    _apply_once('dhcp', tasks, firewall_queues, reload_dhcp,
                 lambda: (dhcp(), ))
-    _apply_once('firewall', firewall_queues, reload_firewall,
+    _apply_once('firewall', tasks, firewall_queues, reload_firewall,
                 lambda: (BuildFirewall().build_ipt()))
-    _apply_once('firewall_vlan', firewall_queues, reload_firewall_vlan,
+    _apply_once('firewall_vlan', tasks, firewall_queues, reload_firewall_vlan,
                 lambda: (vlan(), ))
-    _apply_once('blacklist', firewall_queues, reload_blacklist,
+    _apply_once('blacklist', tasks, firewall_queues, reload_blacklist,
                 lambda: (list(ipset()), ))
 
 
diff --git a/circle/manager/mancelery.py b/circle/manager/mancelery.py
index 3268fd9..ab095fb 100755
--- a/circle/manager/mancelery.py
+++ b/circle/manager/mancelery.py
@@ -16,12 +16,15 @@
 # with CIRCLE.  If not, see <http://www.gnu.org/licenses/>.
 
 from celery import Celery
+from celery.signals import worker_ready
 from datetime import timedelta
 from kombu import Queue, Exchange
 from os import getenv
 
 HOSTNAME = "localhost"
 CACHE_URI = getenv("CACHE_URI", "pylibmc://127.0.0.1:11211/")
+QUEUE_NAME = HOSTNAME + '.man'
+
 
 celery = Celery('manager',
                 broker=getenv("AMQP_URI"),
@@ -57,3 +60,10 @@ celery.conf.update(
     }
 
 )
+
+
+@worker_ready.connect()
+def cleanup_tasks(conf=None, **kwargs):
+    '''Discard all task and clean up activity.'''
+    from vm.models.activity import cleanup
+    cleanup(queue_name=QUEUE_NAME)
diff --git a/circle/manager/moncelery.py b/circle/manager/moncelery.py
index 314ec2e..1ff01c1 100755
--- a/circle/manager/moncelery.py
+++ b/circle/manager/moncelery.py
@@ -16,12 +16,14 @@
 # with CIRCLE.  If not, see <http://www.gnu.org/licenses/>.
 
 from celery import Celery
+from celery.signals import worker_ready
 from datetime import timedelta
 from kombu import Queue, Exchange
 from os import getenv
 
 HOSTNAME = "localhost"
 CACHE_URI = getenv("CACHE_URI", "pylibmc://127.0.0.1:11211/")
+QUEUE_NAME = HOSTNAME + '.monitor'
 
 celery = Celery('monitor',
                 broker=getenv("AMQP_URI"),
@@ -34,7 +36,7 @@ celery.conf.update(
     CELERY_CACHE_BACKEND=CACHE_URI,
     CELERY_TASK_RESULT_EXPIRES=300,
     CELERY_QUEUES=(
-        Queue(HOSTNAME + '.monitor', Exchange('monitor', type='direct'),
+        Queue(QUEUE_NAME, Exchange('monitor', type='direct'),
               routing_key="monitor"),
     ),
     CELERYBEAT_SCHEDULE={
@@ -70,3 +72,10 @@ celery.conf.update(
     }
 
 )
+
+
+@worker_ready.connect()
+def cleanup_tasks(conf=None, **kwargs):
+    '''Discard all task and clean up activity.'''
+    from vm.models.activity import cleanup
+    cleanup(queue_name=QUEUE_NAME)
diff --git a/circle/manager/slowcelery.py b/circle/manager/slowcelery.py
index ee8eba1..c06d7d5 100755
--- a/circle/manager/slowcelery.py
+++ b/circle/manager/slowcelery.py
@@ -16,12 +16,14 @@
 # with CIRCLE.  If not, see <http://www.gnu.org/licenses/>.
 
 from celery import Celery
+from celery.signals import worker_ready
 from datetime import timedelta
 from kombu import Queue, Exchange
 from os import getenv
 
 HOSTNAME = "localhost"
 CACHE_URI = getenv("CACHE_URI", "pylibmc://127.0.0.1:11211/")
+QUEUE_NAME = HOSTNAME + '.man.slow'
 
 celery = Celery('manager.slow',
                 broker=getenv("AMQP_URI"),
@@ -36,7 +38,7 @@ celery.conf.update(
     CELERY_CACHE_BACKEND=CACHE_URI,
     CELERY_TASK_RESULT_EXPIRES=300,
     CELERY_QUEUES=(
-        Queue(HOSTNAME + '.man.slow', Exchange('manager.slow', type='direct'),
+        Queue(QUEUE_NAME, Exchange('manager.slow', type='direct'),
               routing_key="manager.slow"),
     ),
     CELERYBEAT_SCHEDULE={
@@ -48,3 +50,10 @@ celery.conf.update(
     }
 
 )
+
+
+@worker_ready.connect()
+def cleanup_tasks(conf=None, **kwargs):
+    '''Discard all task and clean up activity.'''
+    from vm.models.activity import cleanup
+    cleanup(queue_name=QUEUE_NAME)
diff --git a/circle/storage/models.py b/circle/storage/models.py
index 9a911e4..9809b6f 100644
--- a/circle/storage/models.py
+++ b/circle/storage/models.py
@@ -490,6 +490,9 @@ class Disk(TimeStampedModel):
                     disk.destroy()
                     raise humanize_exception(ugettext_noop(
                         "Operation aborted by user."), e)
+            except:
+                disk.destroy()
+                raise
         disk.is_ready = True
         disk.save()
         return disk
diff --git a/circle/vm/models/activity.py b/circle/vm/models/activity.py
index 55c8fce..ad7736b 100644
--- a/circle/vm/models/activity.py
+++ b/circle/vm/models/activity.py
@@ -20,7 +20,6 @@ from contextlib import contextmanager
 from logging import getLogger
 from warnings import warn
 
-from celery.signals import worker_ready
 from celery.contrib.abortable import AbortableAsyncResult
 
 from django.core.urlresolvers import reverse
@@ -263,17 +262,17 @@ def node_activity(code_suffix, node, task_uuid=None, user=None,
     return activitycontextimpl(act)
 
 
-@worker_ready.connect()
 def cleanup(conf=None, **kwargs):
     # TODO check if other manager workers are running
-    from celery.task.control import discard_all
-    discard_all()
     msg_txt = ugettext_noop("Manager is restarted, activity is cleaned up. "
                             "You can try again now.")
     message = create_readable(msg_txt, msg_txt)
+    queue_name = kwargs.get('queue_name', None)
     for i in InstanceActivity.objects.filter(finished__isnull=True):
-        i.finish(False, result=message)
-        logger.error('Forced finishing stale activity %s', i)
+        op = i.get_operation()
+        if op and op.async_queue == queue_name:
+            i.finish(False, result=message)
+            logger.error('Forced finishing stale activity %s', i)
     for i in NodeActivity.objects.filter(finished__isnull=True):
         i.finish(False, result=message)
         logger.error('Forced finishing stale activity %s', i)
diff --git a/circle/vm/models/node.py b/circle/vm/models/node.py
index 3aea89a..bf82ccc 100644
--- a/circle/vm/models/node.py
+++ b/circle/vm/models/node.py
@@ -313,10 +313,11 @@ class Node(OperatedMixin, TimeStampedModel):
     def get_status_label(self):
         return {
             'OFFLINE': 'label-warning',
-            'DISABLED': 'label-warning',
+            'DISABLED': 'label-danger',
             'MISSING': 'label-danger',
-            'ONLINE': 'label-success'}.get(self.get_state(),
-                                           'label-danger')
+            'ACTIVE': 'label-success',
+            'PASSIVE': 'label-warning',
+        }.get(self.get_state(), 'label-danger')
 
     @node_available
     def update_vm_states(self):
diff --git a/circle/vm/operations.py b/circle/vm/operations.py
index 02feb3a..3228725 100644
--- a/circle/vm/operations.py
+++ b/circle/vm/operations.py
@@ -324,7 +324,7 @@ class DeployOperation(InstanceOperation):
                           "deployed to node: %(node)s"),
             node=self.instance.node)
 
-    def _operation(self, activity, timeout=15):
+    def _operation(self, activity):
         # Allocate VNC port and host node
         self.instance.allocate_vnc_port()
         self.instance.allocate_node()
@@ -405,7 +405,7 @@ class DestroyOperation(InstanceOperation):
     required_perms = ()
     resultant_state = 'DESTROYED'
 
-    def _operation(self, activity):
+    def _operation(self, activity, system):
         # Destroy networks
         with activity.sub_activity(
                 'destroying_net',
@@ -415,7 +415,7 @@ class DestroyOperation(InstanceOperation):
             self.instance.destroy_net()
 
         if self.instance.node:
-            self.instance._delete_vm(parent_activity=activity)
+            self.instance._delete_vm(parent_activity=activity, system=system)
 
         # Destroy disks
         with activity.sub_activity(
@@ -425,7 +425,8 @@ class DestroyOperation(InstanceOperation):
 
         # Delete mem. dump if exists
         try:
-            self.instance._delete_mem_dump(parent_activity=activity)
+            self.instance._delete_mem_dump(parent_activity=activity,
+                                           system=system)
         except:
             pass
 
@@ -470,12 +471,11 @@ class MigrateOperation(RemoteInstanceOperation):
     async_queue = "localhost.man.slow"
     task = vm_tasks.migrate
     remote_queue = ("vm", "slow")
-    timeout = 600
+    remote_timeout = 1000
 
-    def _get_remote_args(self, to_node, **kwargs):
+    def _get_remote_args(self, to_node, live_migration, **kwargs):
         return (super(MigrateOperation, self)._get_remote_args(**kwargs)
-                + [to_node.host.hostname, True])
-        # TODO handle non-live migration
+                + [to_node.host.hostname, live_migration])
 
     def rollback(self, activity):
         with activity.sub_activity(
@@ -483,7 +483,7 @@ class MigrateOperation(RemoteInstanceOperation):
                 "redeploy network (rollback)")):
             self.instance.deploy_net()
 
-    def _operation(self, activity, to_node=None):
+    def _operation(self, activity, to_node=None, live_migration=True):
         if not to_node:
             with activity.sub_activity('scheduling',
                                        readable_name=ugettext_noop(
@@ -495,7 +495,8 @@ class MigrateOperation(RemoteInstanceOperation):
             with activity.sub_activity(
                 'migrate_vm', readable_name=create_readable(
                     ugettext_noop("migrate to %(node)s"), node=to_node)):
-                super(MigrateOperation, self)._operation(to_node=to_node)
+                super(MigrateOperation, self)._operation(
+                    to_node=to_node, live_migration=live_migration)
         except Exception as e:
             if hasattr(e, 'libvirtError'):
                 self.rollback(activity)
@@ -575,6 +576,7 @@ class RemoveDiskOperation(InstanceOperation):
             'destroy_disk',
             readable_name=ugettext_noop('destroy disk')
         ):
+            disk.destroy()
             return self.instance.disks.remove(disk)
 
     def get_activity_name(self, kwargs):
@@ -631,7 +633,7 @@ class SaveAsTemplateOperation(InstanceOperation):
             for disk in self.disks:
                 disk.destroy()
 
-    def _operation(self, activity, user, system, timeout=300, name=None,
+    def _operation(self, activity, user, system, name=None,
                    with_shutdown=True, task=None, **kwargs):
         if with_shutdown:
             try:
@@ -709,7 +711,7 @@ class ShutdownOperation(AbortableRemoteOperationMixin,
     resultant_state = 'STOPPED'
     task = vm_tasks.shutdown
     remote_queue = ("vm", "slow")
-    timeout = 120
+    remote_timeout = 120
 
     def _operation(self, task):
         super(ShutdownOperation, self)._operation(task=task)
@@ -778,12 +780,12 @@ class SleepOperation(InstanceOperation):
         else:
             activity.resultant_state = 'ERROR'
 
-    def _operation(self, activity):
+    def _operation(self, activity, system):
         with activity.sub_activity('shutdown_net',
                                    readable_name=ugettext_noop(
                                        "shutdown network")):
             self.instance.shutdown_net()
-        self.instance._suspend_vm(parent_activity=activity)
+        self.instance._suspend_vm(parent_activity=activity, system=system)
         self.instance.yield_node()
 
     @register_operation
@@ -792,7 +794,7 @@ class SleepOperation(InstanceOperation):
         name = _("suspend virtual machine")
         task = vm_tasks.sleep
         remote_queue = ("vm", "slow")
-        timeout = 600
+        remote_timeout = 1000
 
         def _get_remote_args(self, **kwargs):
             return (super(SleepOperation.SuspendVmOperation, self)
@@ -845,7 +847,7 @@ class WakeUpOperation(InstanceOperation):
         name = _("resume virtual machine")
         task = vm_tasks.wake_up
         remote_queue = ("vm", "slow")
-        timeout = 600
+        remote_timeout = 1000
 
         def _get_remote_args(self, **kwargs):
             return (super(WakeUpOperation.WakeUpVmOperation, self)
diff --git a/circle/vm/tasks/agent_tasks.py b/circle/vm/tasks/agent_tasks.py
index 5528735..db5ad56 100644
--- a/circle/vm/tasks/agent_tasks.py
+++ b/circle/vm/tasks/agent_tasks.py
@@ -53,8 +53,18 @@ def start_access_server(vm):
     pass
 
 
+@celery.task(name='agent.update_legacy')
+def update_legacy(vm, data, executable=None):
+    pass
+
+
+@celery.task(name='agent.append')
+def append(vm, data, filename, chunk_number):
+    pass
+
+
 @celery.task(name='agent.update')
-def update(vm, data):
+def update(vm, filename, executable, checksum):
     pass
 
 
diff --git a/circle/vm/tasks/local_agent_tasks.py b/circle/vm/tasks/local_agent_tasks.py
index deec6cd..f5a678b 100644
--- a/circle/vm/tasks/local_agent_tasks.py
+++ b/circle/vm/tasks/local_agent_tasks.py
@@ -19,11 +19,14 @@ from common.models import create_readable
 from manager.mancelery import celery
 from vm.tasks.agent_tasks import (restart_networking, change_password,
                                   set_time, set_hostname, start_access_server,
-                                  cleanup, update, change_ip)
+                                  cleanup, update, append,
+                                  change_ip, update_legacy)
 from firewall.models import Host
 
 import time
+import os
 from base64 import encodestring
+from hashlib import md5
 from StringIO import StringIO
 from tarfile import TarFile, TarInfo
 from django.conf import settings
@@ -61,17 +64,34 @@ def send_networking_commands(instance, act):
         restart_networking.apply_async(queue=queue, args=(instance.vm_name, ))
 
 
-def create_agent_tar():
+def create_linux_tar():
     def exclude(tarinfo):
-        if tarinfo.name.startswith('./.git'):
+        ignored = ('./.', './misc', './windows')
+        if any(tarinfo.name.startswith(x) for x in ignored):
             return None
         else:
             return tarinfo
 
     f = StringIO()
 
+    with TarFile.open(fileobj=f, mode='w:gz') as tar:
+        agent_path = os.path.join(settings.AGENT_DIR, "agent-linux")
+        tar.add(agent_path, arcname='.', filter=exclude)
+
+        version_fileobj = StringIO(settings.AGENT_VERSION)
+        version_info = TarInfo(name='version.txt')
+        version_info.size = len(version_fileobj.buf)
+        tar.addfile(version_info, version_fileobj)
+
+    return encodestring(f.getvalue()).replace('\n', '')
+
+
+def create_windows_tar():
+    f = StringIO()
+
+    agent_path = os.path.join(settings.AGENT_DIR, "agent-win")
     with TarFile.open(fileobj=f, mode='w|gz') as tar:
-        tar.add(settings.AGENT_DIR, arcname='.', filter=exclude)
+        tar.add(agent_path, arcname='.')
 
         version_fileobj = StringIO(settings.AGENT_VERSION)
         version_info = TarInfo(name='version.txt')
@@ -82,7 +102,7 @@ def create_agent_tar():
 
 
 @celery.task
-def agent_started(vm, version=None):
+def agent_started(vm, version=None, system=None):
     from vm.models import Instance, InstanceActivity
     instance = Instance.objects.get(id=int(vm.split('-')[-1]))
     queue = instance.get_remote_queue_name("agent")
@@ -104,7 +124,7 @@ def agent_started(vm, version=None):
 
         if version and version != settings.AGENT_VERSION:
             try:
-                update_agent(instance, act)
+                update_agent(instance, act, system, settings.AGENT_VERSION)
             except TimeoutError:
                 pass
             else:
@@ -146,11 +166,16 @@ def measure_boot_time(instance):
 @celery.task
 def agent_stopped(vm):
     from vm.models import Instance, InstanceActivity
+    from vm.models.activity import ActivityInProgressError
     instance = Instance.objects.get(id=int(vm.split('-')[-1]))
     qs = InstanceActivity.objects.filter(instance=instance,
                                          activity_code='vm.Instance.agent')
     act = qs.latest('id')
-    with act.sub_activity('stopping', readable_name=ugettext_noop('stopping')):
+    try:
+        with act.sub_activity('stopping',
+                              readable_name=ugettext_noop('stopping')):
+            pass
+    except ActivityInProgressError:
         pass
 
 
@@ -161,7 +186,7 @@ def get_network_configs(instance):
     return (interfaces, settings.FIREWALL_SETTINGS['rdns_ip'])
 
 
-def update_agent(instance, act=None):
+def update_agent(instance, act=None, system=None, version=None):
     if act:
         act = act.sub_activity(
             'update',
@@ -176,6 +201,40 @@ def update_agent(instance, act=None):
                 version=settings.AGENT_VERSION))
     with act:
         queue = instance.get_remote_queue_name("agent")
-        update.apply_async(
-            queue=queue,
-            args=(instance.vm_name, create_agent_tar())).get(timeout=10)
+        if system == "Windows":
+            executable = os.listdir(os.path.join(settings.AGENT_DIR,
+                                                 "agent-win"))[0]
+            # executable = "agent-winservice-%(version)s.exe" % {
+            #   'version': version}
+            data = create_windows_tar()
+        elif system == "Linux":
+            executable = ""
+            data = create_linux_tar()
+        else:
+            executable = ""
+            # Legacy update method
+            return update_legacy.apply_async(
+                queue=queue,
+                args=(instance.vm_name, create_linux_tar())
+            ).get(timeout=60)
+
+        checksum = md5(data).hexdigest()
+        chunk_size = 1024 * 1024
+        chunk_number = 0
+        index = 0
+        filename = version + ".tar"
+        while True:
+            chunk = data[index:index+chunk_size]
+            if chunk:
+                append.apply_async(
+                    queue=queue,
+                    args=(instance.vm_name, chunk,
+                          filename, chunk_number)).get(timeout=60)
+                index = index + chunk_size
+                chunk_number = chunk_number + 1
+            else:
+                update.apply_async(
+                    queue=queue,
+                    args=(instance.vm_name, filename, executable, checksum)
+                ).get(timeout=60)
+                break
diff --git a/circle/vm/tests/test_operations.py b/circle/vm/tests/test_operations.py
index 819ec85..f5eca95 100644
--- a/circle/vm/tests/test_operations.py
+++ b/circle/vm/tests/test_operations.py
@@ -59,7 +59,8 @@ class MigrateOperationTestCase(TestCase):
             MigrateException, op._operation,
             act, to_node=None)
         assert inst.select_node.called
-        op._get_remote_args.assert_called_once_with(to_node='test')
+        op._get_remote_args.assert_called_once_with(
+            to_node='test', live_migration=True)
 
 
 class RebootOperationTestCase(TestCase):
diff --git a/miscellaneous/mancelery.conf b/miscellaneous/mancelery.conf
index a6f63c6..e3dd802 100644
--- a/miscellaneous/mancelery.conf
+++ b/miscellaneous/mancelery.conf
@@ -6,9 +6,14 @@ respawn limit 30 30
 setgid cloud
 setuid cloud
 
+kill timeout 360
+kill signal SIGTERM
+
 script
     cd /home/cloud/circle/circle
     . /home/cloud/.virtualenvs/circle/bin/activate
     . /home/cloud/.virtualenvs/circle/bin/postactivate
-    exec ./manage.py celery --app=manager.mancelery worker --autoreload --loglevel=info --hostname=mancelery -B -c 10
+    ./manage.py celery -f --app=manager.mancelery purge
+    exec ./manage.py celery --app=manager.mancelery worker --autoreload --loglevel=info --hostname=mancelery -B -c 3
 end script
+
diff --git a/miscellaneous/moncelery.conf b/miscellaneous/moncelery.conf
index ca00325..7c107c1 100644
--- a/miscellaneous/moncelery.conf
+++ b/miscellaneous/moncelery.conf
@@ -3,6 +3,7 @@ description     "CIRCLE moncelery for monitoring jobs"
 respawn
 respawn limit 30 30
 
+
 setgid cloud
 setuid cloud
 
@@ -10,5 +11,7 @@ script
     cd /home/cloud/circle/circle
     . /home/cloud/.virtualenvs/circle/bin/activate
     . /home/cloud/.virtualenvs/circle/bin/postactivate
-    exec ./manage.py celery --app=manager.moncelery worker --autoreload --loglevel=info --hostname=moncelery -B -c 3
+    ./manage.py celery -f --app=manager.moncelery purge
+    exec ./manage.py celery --app=manager.moncelery worker --autoreload --loglevel=info --hostname=moncelery -B -c 2
 end script
+
diff --git a/miscellaneous/slowcelery.conf b/miscellaneous/slowcelery.conf
index b4fdc75..e8c16c1 100644
--- a/miscellaneous/slowcelery.conf
+++ b/miscellaneous/slowcelery.conf
@@ -1,4 +1,4 @@
-description     "CIRCLE mancelery for slow jobs"
+description     "CIRCLE slowcelery for resource intensive or long  jobs"
 
 respawn
 respawn limit 30 30
@@ -6,9 +6,15 @@ respawn limit 30 30
 setgid cloud
 setuid cloud
 
+kill timeout 360                                                                                      
+kill signal INT 
+                                          
+
 script
     cd /home/cloud/circle/circle
     . /home/cloud/.virtualenvs/circle/bin/activate
     . /home/cloud/.virtualenvs/circle/bin/postactivate
-    exec ./manage.py celery --app=manager.slowcelery worker --autoreload --loglevel=info --hostname=slowcelery -B -c 5
+    ./manage.py celery -f --app=manager.slowcelery purge
+    exec ./manage.py celery --app=manager.slowcelery worker --autoreload --loglevel=info --hostname=slowcelery -B -c 1
 end script
+