Commit db560b90 by Őry Máté

Merge branch 'master' into feature-mass-ops

parents 9f4783eb 106f963d
...@@ -368,9 +368,9 @@ if get_env_variable('DJANGO_SAML', 'FALSE') == 'TRUE': ...@@ -368,9 +368,9 @@ if get_env_variable('DJANGO_SAML', 'FALSE') == 'TRUE':
from shutilwhich import which from shutilwhich import which
from saml2 import BINDING_HTTP_POST, BINDING_HTTP_REDIRECT from saml2 import BINDING_HTTP_POST, BINDING_HTTP_REDIRECT
# INSTALLED_APPS += ( # needed only for testing djangosaml2 INSTALLED_APPS += (
# 'djangosaml', 'djangosaml2',
# ) )
AUTHENTICATION_BACKENDS = ( AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend', 'django.contrib.auth.backends.ModelBackend',
'djangosaml2.backends.Saml2Backend', 'djangosaml2.backends.Saml2Backend',
......
...@@ -634,12 +634,8 @@ class LeaseForm(forms.ModelForm): ...@@ -634,12 +634,8 @@ class LeaseForm(forms.ModelForm):
Field('name'), Field('name'),
Field("suspend_interval_seconds", type="hidden", value="0"), Field("suspend_interval_seconds", type="hidden", value="0"),
Field("delete_interval_seconds", type="hidden", value="0"), Field("delete_interval_seconds", type="hidden", value="0"),
HTML(string_concat("<label>", _("Suspend in"), "</label>")),
Div( Div(
Div(
HTML(_("Suspend in")),
css_class="input-group-addon",
style="width: 100px;",
),
NumberField("suspend_hours", css_class="form-control"), NumberField("suspend_hours", css_class="form-control"),
Div( Div(
HTML(_("hours")), HTML(_("hours")),
...@@ -662,12 +658,8 @@ class LeaseForm(forms.ModelForm): ...@@ -662,12 +658,8 @@ class LeaseForm(forms.ModelForm):
), ),
css_class="input-group interval-input", css_class="input-group interval-input",
), ),
HTML(string_concat("<label>", _("Delete in"), "</label>")),
Div( Div(
Div(
HTML(_("Delete in")),
css_class="input-group-addon",
style="width: 100px;",
),
NumberField("delete_hours", css_class="form-control"), NumberField("delete_hours", css_class="form-control"),
Div( Div(
HTML(_("hours")), HTML(_("hours")),
...@@ -691,7 +683,7 @@ class LeaseForm(forms.ModelForm): ...@@ -691,7 +683,7 @@ class LeaseForm(forms.ModelForm):
css_class="input-group interval-input", css_class="input-group interval-input",
) )
) )
helper.add_input(Submit("submit", "Save changes")) helper.add_input(Submit("submit", _("Save changes")))
return helper return helper
class Meta: class Meta:
...@@ -703,6 +695,8 @@ class VmRenewForm(forms.Form): ...@@ -703,6 +695,8 @@ class VmRenewForm(forms.Form):
force = forms.BooleanField(required=False, label=_( force = forms.BooleanField(required=False, label=_(
"Set expiration times even if they are shorter than " "Set expiration times even if they are shorter than "
"the current value.")) "the current value."))
save = forms.BooleanField(required=False, label=_(
"Save selected lease."))
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
choices = kwargs.pop('choices') choices = kwargs.pop('choices')
...@@ -714,6 +708,32 @@ class VmRenewForm(forms.Form): ...@@ -714,6 +708,32 @@ class VmRenewForm(forms.Form):
empty_label=None, label=_('Length'))) empty_label=None, label=_('Length')))
if len(choices) < 2: if len(choices) < 2:
self.fields['lease'].widget = HiddenInput() self.fields['lease'].widget = HiddenInput()
self.fields['save'].widget = HiddenInput()
@property
def helper(self):
helper = FormHelper(self)
helper.form_tag = False
return helper
class VmStateChangeForm(forms.Form):
interrupt = forms.BooleanField(required=False, label=_(
"Forcibly interrupt all running activities."),
help_text=_("Set all activities to finished state, "
"but don't interrupt any tasks."))
new_state = forms.ChoiceField(Instance.STATUS, label=_(
"New status"))
def __init__(self, *args, **kwargs):
show_interrupt = kwargs.pop('show_interrupt')
status = kwargs.pop('status')
super(VmStateChangeForm, self).__init__(*args, **kwargs)
if not show_interrupt:
self.fields['interrupt'].widget = HiddenInput()
self.fields['new_state'].initial = status
@property @property
def helper(self): def helper(self):
...@@ -1141,9 +1161,9 @@ class VmResourcesForm(forms.ModelForm): ...@@ -1141,9 +1161,9 @@ class VmResourcesForm(forms.ModelForm):
vm_search_choices = ( vm_search_choices = (
(0, _("owned")), ("owned", _("owned")),
(1, _("shared")), ("shared", _("shared")),
(2, _("all")), ("all", _("all")),
) )
...@@ -1162,5 +1182,5 @@ class VmListSearchForm(forms.Form): ...@@ -1162,5 +1182,5 @@ class VmListSearchForm(forms.Form):
# set initial value, otherwise it would be overwritten by request.GET # set initial value, otherwise it would be overwritten by request.GET
if not self.data.get("stype"): if not self.data.get("stype"):
data = self.data.copy() data = self.data.copy()
data['stype'] = 2 data['stype'] = "all"
self.data = data self.data = data
...@@ -262,7 +262,7 @@ $(function () { ...@@ -262,7 +262,7 @@ $(function () {
$("#dashboard-vm-search-form").submit(function() { $("#dashboard-vm-search-form").submit(function() {
var vm_list_items = $("#dashboard-vm-list .list-group-item"); var vm_list_items = $("#dashboard-vm-list .list-group-item");
if(vm_list_items.length == 1) { if(vm_list_items.length == 1 && vm_list_items.first().prop("href")) {
window.location.href = vm_list_items.first().prop("href"); window.location.href = vm_list_items.first().prop("href");
return false; return false;
} }
......
var ctrlDown, shiftDown = false;
var ctrlKey = 17;
var shiftKey = 16;
var selected = [];
$(function() { $(function() {
$(document).keydown(function(e) {
if (e.keyCode == ctrlKey) ctrlDown = true;
if (e.keyCode == shiftKey) shiftDown = true;
}).keyup(function(e) {
if (e.keyCode == ctrlKey) ctrlDown = false;
if (e.keyCode == shiftKey) shiftDown = false;
});
$('.group-list-table tbody').find('tr').mousedown(function() {
var retval = true;
if (ctrlDown) {
setRowColor($(this));
if(!$(this).hasClass('group-list-selected')) {
selected.splice(selected.indexOf($(this).index()), 1);
} else {
selected.push($(this).index());
}
retval = false;
} else if(shiftDown) {
if(selected.length > 0) {
start = selected[selected.length - 1] + 1;
end = $(this).index();
if(start > end) {
var tmp = start - 1; start = end; end = tmp - 1;
}
for(var i = start; i <= end; i++) {
if(selected.indexOf(i) < 0) {
selected.push(i);
setRowColor($('.group-list-table tbody tr').eq(i));
}
}
}
retval = false;
} else {
$('.group-list-selected').removeClass('group-list-selected');
$(this).addClass('group-list-selected');
selected = [$(this).index()];
}
// reset btn disables
$('.group-list-table tbody tr .btn').attr('disabled', false);
// show/hide group controls
if(selected.length > 1) {
$('.group-list-group-control a').attr('disabled', false);
for(var i = 0; i < selected.length; i++) {
$('.group-list-table tbody tr').eq(selected[i]).find('.btn').attr('disabled', true);
}
} else {
$('.group-list-group-control a').attr('disabled', true);
}
return retval;
});
$('#group-list-group-migrate').click(function() {
console.log(collectIds(selected));
});
$('tbody a').mousedown(function(e) {
// parent tr doesn't get selected when clicked
e.stopPropagation();
});
$('tbody a').click(function(e) {
// browser doesn't jump to top when clicked the buttons
if(!$(this).hasClass('real-link')) {
return false;
}
});
/* rename */ /* rename */
$("#group-list-rename-button, .group-details-rename-button").click(function() { $("#group-list-rename-button, .group-details-rename-button").click(function() {
$("#group-list-column-name", $(this).closest("tr")).hide(); $("#group-list-column-name", $(this).closest("tr")).hide();
...@@ -113,51 +34,4 @@ $(function() { ...@@ -113,51 +34,4 @@ $(function() {
return false; return false;
}); });
/* group actions */
/* select all */
$('#group-list-group-select-all').click(function() {
$('.group-list-table tbody tr').each(function() {
var index = $(this).index();
if(selected.indexOf(index) < 0) {
selected.push(index);
$(this).addClass('group-list-selected');
}
});
if(selected.length > 0)
$('.group-list-group-control a').attr('disabled', false);
return false;
});
/* mass vm delete */
$('#group-list-group-delete').click(function() {
addModalConfirmation(massDeleteVm,
{
'url': '/dashboard/group/mass-delete/',
'data': {
'selected': selected,
'v': collectIds(selected)
}
}
);
return false;
});
}); });
function collectIds(rows) {
var ids = [];
for(var i = 0; i < rows.length; i++) {
var div = $('td:first-child div', $('.group-list-table tbody tr').eq(rows[i]));
ids.push(div.prop('id').replace('node-', ''));
}
return ids;
}
function setRowColor(row) {
if(!row.hasClass('group-list-selected')) {
row.addClass('group-list-selected');
} else {
row.removeClass('group-list-selected');
}
}
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
{% csrf_token %} {% csrf_token %}
{{ vm_create_form.template }} {{ vm_create_form.template }}
{{ vm_create_form.customized }}
<div class="row"> <div class="row">
<div class="col-sm-12"> <div class="col-sm-12">
...@@ -23,6 +22,8 @@ ...@@ -23,6 +22,8 @@
</div> </div>
</div> </div>
{% if perms.vm.set_resources %}
{{ vm_create_form.customized }}
<div class="row"> <div class="row">
<div class="col-sm-10"> <div class="col-sm-10">
<div class="form-group"> <div class="form-group">
...@@ -85,6 +86,7 @@ ...@@ -85,6 +86,7 @@
</div><!-- .no-js-hidden --> </div><!-- .no-js-hidden -->
</div><!-- .col-sm-8 --> </div><!-- .col-sm-8 -->
</div><!-- .row --> </div><!-- .row -->
{% endif %}
</form> </form>
<script> <script>
......
...@@ -6,63 +6,24 @@ ...@@ -6,63 +6,24 @@
{% block content %} {% block content %}
<div class="alert alert-info">
Tip #1: you can select multiple vm instances while holding down the <strong>CTRL</strong> key!
</div>
<div class="alert alert-info">
Tip #2: if you want to select multiple instances by one click select an instance then hold down <strong>SHIFT</strong> key and select another one!
</div>
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<h3 class="no-margin"><i class="fa fa-group"></i> Your groups</h3> <h3 class="no-margin"><i class="fa fa-group"></i> Your groups</h3>
</div> </div>
<div class="panel-body group-list-group-control"> <div class="panel-body">
<p>
<strong>Group actions</strong>
<button id="group-list-group-select-all" class="btn btn-info btn-xs">Select all</button>
<a id="group-list-group-delete" disabled href="#" class="btn btn-danger btn-xs"><i class="fa fa-times"></i> Discard</a>
</p>
</div>
<div id="table_container"> <div id="table_container">
<div id="rendered_table" class="panel-body"> <div id="rendered_table" class="panel-body">
{% render_table table %} {% render_table table %}
</div> </div>
</div> </div>
</div><!-- .panel-body -->
</div> </div>
</div> </div>
</div> </div>
<style>
.popover {
max-width: 600px;
}
.group-list-selected, .group-list-selected td {
background-color: #e8e8e8 !important;
}
.group-list-selected:hover, .group-list-selected:hover td {
background-color: #d0d0d0 !important;
}
.group-list-selected td:first-child {
font-weight: bold;
}
.group-list-table-thin {
width: 10px;
}
.group-list-table-admin {
width: 130px;
}
</style>
{% endblock %} {% endblock %}
{% block extra_js %} {% block extra_js %}
<script src="{{ STATIC_URL}}dashboard/group-list.js"></script> <script src="{{ STATIC_URL}}dashboard/group-list.js"></script>
{% endblock %} {% endblock %}
<a data-group-pk="{{ record.pk }}" class="btn btn-danger btn-xs real-link group-delete" href="{% url "dashboard.views.delete-group" pk=record.pk %}?next={{ request.path }}"><i class="fa fa-trash"></i></a> <a data-group-pk="{{ record.pk }}"
class="btn btn-danger btn-xs real-link group-delete"
href="{% url "dashboard.views.delete-group" pk=record.pk %}?next={{ request.path }}">
<i class="fa fa-trash-o"></i>
</a>
...@@ -3,8 +3,10 @@ ...@@ -3,8 +3,10 @@
<div class="panel-heading"> <div class="panel-heading">
<div class="pull-right toolbar"> <div class="pull-right toolbar">
<div class="btn-group"> <div class="btn-group">
<a href="#index-graph-view" data-index-box="node" class="btn btn-default btn-xs"><i class="fa fa-dashboard"></i></a> <a href="#index-graph-view" data-index-box="node" class="btn btn-default btn-xs"
<a href="#index-list-view" data-index-box="node" class="btn btn-default btn-xs disabled"><i class="fa fa-list"></i></a> 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> </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>
......
...@@ -3,10 +3,12 @@ ...@@ -3,10 +3,12 @@
<div class="panel-heading"> <div class="panel-heading">
<div class="pull-right toolbar"> <div class="pull-right toolbar">
<div class="btn-group"> <div class="btn-group">
<a href="#index-graph-view" data-index-box="vm" class="btn <a href="#index-graph-view" data-index-box="vm" class="btn btn-default btn-xs"
btn-default btn-xs" title="{% trans "summary view" %}"><i class="fa fa-dashboard"></i></a> data-container="body"
<a href="#index-list-view" data-index-box="vm" class="btn title="{% trans "summary view" %}"><i class="fa fa-dashboard"></i></a>
btn-default btn-xs disabled" title="{% trans "list view" %}"><i class="fa fa-list"></i></a> <a href="#index-list-view" data-index-box="vm" class="btn btn-default btn-xs disabled"
data-container="body"
title="{% trans "list view" %}"><i class="fa fa-list"></i></a>
</div> </div>
<span class="btn btn-default btn-xs infobtn" title="{% trans "List of your current virtual machines. Favourited ones are ahead of others." %}"><i class="fa fa-info-circle"></i></span> <span class="btn btn-default btn-xs infobtn" title="{% trans "List of your current virtual machines. Favourited ones are ahead of others." %}"><i class="fa fa-info-circle"></i></span>
</div> </div>
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
<span class="operation operation-{{op.op}} btn btn-default disabled btn-xs"> <span class="operation operation-{{op.op}} btn btn-default disabled btn-xs">
{% else %} {% else %}
<a href="{{op.get_url}}" class="operation operation-{{op.op}} btn <a href="{{op.get_url}}" class="operation operation-{{op.op}} btn
btn-{{op.effect}} btn-xs" title="{{op.name|capfirst}}: {{op.description|truncatewords:20}}"> btn-{{op.effect}} btn-xs" title="{{op.name|capfirst}}: {{op.description|truncatewords:15}}">
{% endif %} {% endif %}
<i class="fa fa-{{op.icon}}"></i> <i class="fa fa-{{op.icon}}"></i>
<span{% if not op.is_preferred %} class="sr-only"{% endif %}>{{op.name}}</span> <span{% if not op.is_preferred %} class="sr-only"{% endif %}>{{op.name}}</span>
......
...@@ -67,7 +67,7 @@ from .forms import ( ...@@ -67,7 +67,7 @@ from .forms import (
CircleAuthenticationForm, HostForm, LeaseForm, MyProfileForm, CircleAuthenticationForm, HostForm, LeaseForm, MyProfileForm,
NodeForm, TemplateForm, TraitForm, VmCustomizeForm, GroupCreateForm, NodeForm, TemplateForm, TraitForm, VmCustomizeForm, GroupCreateForm,
UserCreationForm, GroupProfileUpdateForm, UnsubscribeForm, UserCreationForm, GroupProfileUpdateForm, UnsubscribeForm,
VmSaveForm, UserKeyForm, VmRenewForm, VmSaveForm, UserKeyForm, VmRenewForm, VmStateChangeForm,
CirclePasswordChangeForm, VmCreateDiskForm, VmDownloadDiskForm, CirclePasswordChangeForm, VmCreateDiskForm, VmDownloadDiskForm,
TraitsForm, RawDataForm, GroupPermissionForm, AclUserAddForm, TraitsForm, RawDataForm, GroupPermissionForm, AclUserAddForm,
VmResourcesForm, VmAddInterfaceForm, VmListSearchForm VmResourcesForm, VmAddInterfaceForm, VmListSearchForm
...@@ -936,6 +936,24 @@ class VmRenewView(FormOperationMixin, TokenOperationView, VmOperationView): ...@@ -936,6 +936,24 @@ class VmRenewView(FormOperationMixin, TokenOperationView, VmOperationView):
return extra return extra
class VmStateChangeView(FormOperationMixin, VmOperationView):
op = 'emergency_change_state'
icon = 'legal'
effect = 'danger'
show_in_toolbar = True
form_class = VmStateChangeForm
wait_for_result = 0.5
def get_form_kwargs(self):
inst = self.get_op().instance
active_activities = InstanceActivity.objects.filter(
finished__isnull=True, instance=inst)
show_interrupt = active_activities.exists()
val = super(VmStateChangeView, self).get_form_kwargs()
val.update({'show_interrupt': show_interrupt, 'status': inst.status})
return val
vm_ops = OrderedDict([ vm_ops = OrderedDict([
('deploy', VmOperationView.factory( ('deploy', VmOperationView.factory(
op='deploy', icon='play', effect='success')), op='deploy', icon='play', effect='success')),
...@@ -956,8 +974,7 @@ vm_ops = OrderedDict([ ...@@ -956,8 +974,7 @@ vm_ops = OrderedDict([
op='shut_off', icon='ban', effect='warning')), op='shut_off', icon='ban', effect='warning')),
('recover', VmOperationView.factory( ('recover', VmOperationView.factory(
op='recover', icon='medkit', effect='warning')), op='recover', icon='medkit', effect='warning')),
('nostate', VmOperationView.factory( ('nostate', VmStateChangeView),
op='emergency_change_state', icon='legal', effect='danger')),
('destroy', VmOperationView.factory( ('destroy', VmOperationView.factory(
extra_bases=[TokenOperationView], extra_bases=[TokenOperationView],
op='destroy', icon='times', effect='danger')), op='destroy', icon='times', effect='danger')),
...@@ -1764,10 +1781,10 @@ class VmList(LoginRequiredMixin, FilterMixin, ListView): ...@@ -1764,10 +1781,10 @@ class VmList(LoginRequiredMixin, FilterMixin, ListView):
def create_default_queryset(self): def create_default_queryset(self):
cleaned_data = self.search_form.cleaned_data cleaned_data = self.search_form.cleaned_data
stype = cleaned_data.get('stype', 2) stype = cleaned_data.get('stype', "all")
superuser = stype == 2 superuser = stype == "all"
shared = stype == 1 shared = stype == "shared"
level = "owner" if stype == 0 else "user" level = "owner" if stype == "owned" else "user"
queryset = Instance.get_objects_with_level( queryset = Instance.get_objects_with_level(
level, self.request.user, level, self.request.user,
group_also=shared, disregard_superuser=not superuser, group_also=shared, disregard_superuser=not superuser,
...@@ -2048,8 +2065,10 @@ class VmCreate(LoginRequiredMixin, TemplateView): ...@@ -2048,8 +2065,10 @@ class VmCreate(LoginRequiredMixin, TemplateView):
if not template.has_level(request.user, 'user'): if not template.has_level(request.user, 'user'):
raise PermissionDenied() raise PermissionDenied()
instances = [Instance.create_from_template( args = {"template": template, "owner": user}
template=template, owner=user)] if "name" in request.POST:
args["name"] = request.POST.get("name")
instances = [Instance.create_from_template(**args)]
return self.__deploy(request, instances) return self.__deploy(request, instances)
def __create_customized(self, request, *args, **kwargs): def __create_customized(self, request, *args, **kwargs):
...@@ -2075,6 +2094,7 @@ class VmCreate(LoginRequiredMixin, TemplateView): ...@@ -2075,6 +2094,7 @@ class VmCreate(LoginRequiredMixin, TemplateView):
'num_cores': post['cpu_count'], 'num_cores': post['cpu_count'],
'ram_size': post['ram_size'], 'ram_size': post['ram_size'],
'priority': post['cpu_priority'], 'priority': post['cpu_priority'],
'max_ram_size': post['ram_size'],
} }
networks = [InterfaceTemplate(vlan=l, managed=l.managed) networks = [InterfaceTemplate(vlan=l, managed=l.managed)
for l in post['networks']] for l in post['networks']]
......
...@@ -203,12 +203,6 @@ class Rule(models.Model): ...@@ -203,12 +203,6 @@ class Rule(models.Model):
elif self.firewall_id: elif self.firewall_id:
return 'INPUT' if self.direction == 'in' else 'OUTPUT' return 'INPUT' if self.direction == 'in' else 'OUTPUT'
def get_dport_sport(self):
if self.direction == 'in':
return self.dport, self.sport
else:
return self.sport, self.dport
def get_ipt_rules(self, host=None): def get_ipt_rules(self, host=None):
# action # action
action = 'LOG_ACC' if self.action == 'accept' else 'LOG_DROP' action = 'LOG_ACC' if self.action == 'accept' else 'LOG_DROP'
...@@ -235,9 +229,6 @@ class Rule(models.Model): ...@@ -235,9 +229,6 @@ class Rule(models.Model):
if vlan and not vlan.managed: if vlan and not vlan.managed:
return retval return retval
# src and dst ports
dport, sport = self.get_dport_sport()
# process foreign vlans # process foreign vlans
for foreign_vlan in self.foreign_network.vlans.all(): for foreign_vlan in self.foreign_network.vlans.all():
if not foreign_vlan.managed: if not foreign_vlan.managed:
...@@ -246,7 +237,7 @@ class Rule(models.Model): ...@@ -246,7 +237,7 @@ class Rule(models.Model):
r = IptRule(priority=self.weight, action=action, r = IptRule(priority=self.weight, action=action,
proto=self.proto, extra=self.extra, proto=self.proto, extra=self.extra,
comment='Rule #%s' % self.pk, comment='Rule #%s' % self.pk,
src=src, dst=dst, dport=dport, sport=sport) src=src, dst=dst, dport=self.dport, sport=self.sport)
chain_name = self.get_chain_name(local=vlan, remote=foreign_vlan) chain_name = self.get_chain_name(local=vlan, remote=foreign_vlan)
retval[chain_name] = r retval[chain_name] = r
......
...@@ -745,7 +745,7 @@ class RenewOperation(InstanceOperation): ...@@ -745,7 +745,7 @@ class RenewOperation(InstanceOperation):
required_perms = () required_perms = ()
concurrency_check = False concurrency_check = False
def _operation(self, activity, lease=None, force=False): def _operation(self, activity, lease=None, force=False, save=False):
suspend, delete = self.instance.get_renew_times(lease) suspend, delete = self.instance.get_renew_times(lease)
if (not force and suspend and self.instance.time_of_suspend and if (not force and suspend and self.instance.time_of_suspend and
suspend < self.instance.time_of_suspend): suspend < self.instance.time_of_suspend):
...@@ -759,6 +759,8 @@ class RenewOperation(InstanceOperation): ...@@ -759,6 +759,8 @@ class RenewOperation(InstanceOperation):
"in its delete time get earlier than before.")) "in its delete time get earlier than before."))
self.instance.time_of_suspend = suspend self.instance.time_of_suspend = suspend
self.instance.time_of_delete = delete self.instance.time_of_delete = delete
if save:
self.instance.lease = lease
self.instance.save() self.instance.save()
activity.result = create_readable(ugettext_noop( activity.result = create_readable(ugettext_noop(
"Renewed to suspend at %(suspend)s and destroy at %(delete)s."), "Renewed to suspend at %(suspend)s and destroy at %(delete)s."),
...@@ -779,9 +781,17 @@ class ChangeStateOperation(InstanceOperation): ...@@ -779,9 +781,17 @@ class ChangeStateOperation(InstanceOperation):
"resources.") "resources.")
acl_level = "owner" acl_level = "owner"
required_perms = ('vm.emergency_change_state', ) required_perms = ('vm.emergency_change_state', )
concurrency_check = False
def _operation(self, user, activity, new_state="NOSTATE"): def _operation(self, user, activity, new_state="NOSTATE", interrupt=False):
activity.resultant_state = new_state activity.resultant_state = new_state
if interrupt:
msg_txt = ugettext_noop("Activity is forcibly interrupted.")
message = create_readable(msg_txt, msg_txt)
for i in InstanceActivity.objects.filter(
finished__isnull=True, instance=self.instance):
i.finish(False, result=message)
logger.error('Forced finishing activity %s', i)
register_operation(ChangeStateOperation) register_operation(ChangeStateOperation)
......
...@@ -86,7 +86,7 @@ def agent_started(vm, version=None): ...@@ -86,7 +86,7 @@ def agent_started(vm, version=None):
if version and version != settings.AGENT_VERSION: if version and version != settings.AGENT_VERSION:
try: try:
update_agent(vm, instance, act) update_agent(instance, act)
except TimeoutError: except TimeoutError:
pass pass
else: else:
...@@ -134,9 +134,9 @@ def agent_stopped(vm): ...@@ -134,9 +134,9 @@ def agent_stopped(vm):
pass pass
def update_agent(instance, vm, act=None): def update_agent(instance, act=None):
if act: if act:
act.sub_activity( act = act.sub_activity(
'update', 'update',
readable_name=create_readable( readable_name=create_readable(
ugettext_noop('update to %(version)s'), ugettext_noop('update to %(version)s'),
...@@ -150,5 +150,6 @@ def update_agent(instance, vm, act=None): ...@@ -150,5 +150,6 @@ def update_agent(instance, vm, act=None):
version=settings.AGENT_VERSION)) version=settings.AGENT_VERSION))
with act: with act:
queue = instance.get_remote_queue_name("agent") queue = instance.get_remote_queue_name("agent")
update.apply_async(queue=queue, update.apply_async(
args=(vm, create_agent_tar())).get(timeout=10) queue=queue,
args=(instance.vm_name, create_agent_tar())).get(timeout=10)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment