Commit d3fc9a1f by Csók Tamás

Merge remote-tracking branch 'origin/master' into issue-218

parents 94ae9469 d4c7fdc3
...@@ -32,6 +32,7 @@ from django.core.serializers.json import DjangoJSONEncoder ...@@ -32,6 +32,7 @@ from django.core.serializers.json import DjangoJSONEncoder
from django.db.models import ( from django.db.models import (
CharField, DateTimeField, ForeignKey, NullBooleanField CharField, DateTimeField, ForeignKey, NullBooleanField
) )
from django.template import defaultfilters
from django.utils import timezone from django.utils import timezone
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils.functional import Promise from django.utils.functional import Promise
...@@ -428,6 +429,14 @@ class HumanReadableObject(object): ...@@ -428,6 +429,14 @@ class HumanReadableObject(object):
admin_text_template = admin_text_template._proxy____args[0] admin_text_template = admin_text_template._proxy____args[0]
self.user_text_template = user_text_template self.user_text_template = user_text_template
self.admin_text_template = admin_text_template self.admin_text_template = admin_text_template
for k, v in params.iteritems():
try:
v = timezone.datetime.strptime(
v, "%Y-%m-%dT%H:%M:%S.%fZ").replace(tzinfo=timezone.UTC())
except (ValueError, TypeError): # Mock raises TypeError
pass
if isinstance(v, timezone.datetime):
params[k] = defaultfilters.date(v, "DATETIME_FORMAT")
self.params = params self.params = params
@classmethod @classmethod
...@@ -444,24 +453,27 @@ class HumanReadableObject(object): ...@@ -444,24 +453,27 @@ class HumanReadableObject(object):
def from_dict(cls, d): def from_dict(cls, d):
return None if d is None else cls(**d) return None if d is None else cls(**d)
def get_admin_text(self): def _get_parsed_text(self, key):
if self.admin_text_template == "": value = getattr(self, key)
if value == "":
return "" return ""
try: try:
return _(self.admin_text_template) % self.params return _(value) % self.params
except KeyError:
logger.exception("Can't render %s '%s' %% %s",
key, value, unicode(self.params))
raise
def get_admin_text(self):
try:
return self._get_parsed_text("admin_text_template")
except KeyError: except KeyError:
logger.exception("Can't render admin_text_template '%s' %% %s",
self.admin_text_template, unicode(self.params))
return self.get_user_text() return self.get_user_text()
def get_user_text(self): def get_user_text(self):
if self.user_text_template == "":
return ""
try: try:
return _(self.user_text_template) % self.params return self._get_parsed_text("user_text_template")
except KeyError: except KeyError:
logger.exception("Can't render user_text_template '%s' %% %s",
self.user_text_template, unicode(self.params))
return self.user_text_template return self.user_text_template
def get_text(self, user): def get_text(self, user):
......
...@@ -71,9 +71,7 @@ priority_choices = ( ...@@ -71,9 +71,7 @@ priority_choices = (
) )
class VmSaveForm(forms.Form): class NoFormTagMixin(object):
name = forms.CharField(max_length=100, label=_('Name'),
help_text=_('Human readable name of template.'))
@property @property
def helper(self): def helper(self):
...@@ -81,6 +79,15 @@ class VmSaveForm(forms.Form): ...@@ -81,6 +79,15 @@ class VmSaveForm(forms.Form):
helper.form_tag = False helper.form_tag = False
return helper return helper
class OperationForm(NoFormTagMixin, forms.Form):
pass
class VmSaveForm(OperationForm):
name = forms.CharField(max_length=100, label=_('Name'),
help_text=_('Human readable name of template.'))
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
default = kwargs.pop('default', None) default = kwargs.pop('default', None)
super(VmSaveForm, self).__init__(*args, **kwargs) super(VmSaveForm, self).__init__(*args, **kwargs)
...@@ -193,7 +200,7 @@ class VmCustomizeForm(forms.Form): ...@@ -193,7 +200,7 @@ class VmCustomizeForm(forms.Form):
del self.cleaned_data[name] del self.cleaned_data[name]
class GroupCreateForm(forms.ModelForm): class GroupCreateForm(NoFormTagMixin, forms.ModelForm):
description = forms.CharField(label=_("Description"), required=False, description = forms.CharField(label=_("Description"), required=False,
widget=forms.Textarea(attrs={'rows': 3})) widget=forms.Textarea(attrs={'rows': 3}))
...@@ -232,9 +239,8 @@ class GroupCreateForm(forms.ModelForm): ...@@ -232,9 +239,8 @@ class GroupCreateForm(forms.ModelForm):
@property @property
def helper(self): def helper(self):
helper = FormHelper(self) helper = super(GroupCreateForm, self).helper
helper.add_input(Submit("submit", _("Create"))) helper.add_input(Submit("submit", _("Create")))
helper.form_tag = False
return helper return helper
class Meta: class Meta:
...@@ -242,7 +248,7 @@ class GroupCreateForm(forms.ModelForm): ...@@ -242,7 +248,7 @@ class GroupCreateForm(forms.ModelForm):
fields = ('name', ) fields = ('name', )
class GroupProfileUpdateForm(forms.ModelForm): class GroupProfileUpdateForm(NoFormTagMixin, forms.ModelForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
new_groups = kwargs.pop('new_groups', None) new_groups = kwargs.pop('new_groups', None)
...@@ -261,9 +267,8 @@ class GroupProfileUpdateForm(forms.ModelForm): ...@@ -261,9 +267,8 @@ class GroupProfileUpdateForm(forms.ModelForm):
@property @property
def helper(self): def helper(self):
helper = FormHelper(self) helper = super(GroupProfileUpdateForm, self).helper
helper.add_input(Submit("submit", _("Save"))) helper.add_input(Submit("submit", _("Save")))
helper.form_tag = False
return helper return helper
def save(self, commit=True): def save(self, commit=True):
...@@ -278,17 +283,16 @@ class GroupProfileUpdateForm(forms.ModelForm): ...@@ -278,17 +283,16 @@ class GroupProfileUpdateForm(forms.ModelForm):
fields = ('description', 'org_id') fields = ('description', 'org_id')
class HostForm(forms.ModelForm): class HostForm(NoFormTagMixin, forms.ModelForm):
def setowner(self, user): def setowner(self, user):
self.instance.owner = user self.instance.owner = user
def __init__(self, *args, **kwargs): @property
super(HostForm, self).__init__(*args, **kwargs) def helper(self):
self.helper = FormHelper(self) helper = super(HostForm, self).helper
self.helper.form_show_labels = False helper.form_show_labels = False
self.helper.form_tag = False helper.layout = Layout(
self.helper.layout = Layout(
Div( Div(
Div( # host Div( # host
Div( Div(
...@@ -345,6 +349,7 @@ class HostForm(forms.ModelForm): ...@@ -345,6 +349,7 @@ class HostForm(forms.ModelForm):
), ),
), ),
) )
return helper
class Meta: class Meta:
model = Host model = Host
...@@ -725,7 +730,7 @@ class LeaseForm(forms.ModelForm): ...@@ -725,7 +730,7 @@ class LeaseForm(forms.ModelForm):
model = Lease model = Lease
class VmRenewForm(forms.Form): class VmRenewForm(OperationForm):
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 "
...@@ -745,16 +750,15 @@ class VmRenewForm(forms.Form): ...@@ -745,16 +750,15 @@ class VmRenewForm(forms.Form):
self.fields['lease'].widget = HiddenInput() self.fields['lease'].widget = HiddenInput()
self.fields['save'].widget = HiddenInput() self.fields['save'].widget = HiddenInput()
@property
def helper(self):
helper = FormHelper(self)
helper.form_tag = False
return helper
class VmMigrateForm(forms.Form): class VmMigrateForm(forms.Form):
live_migration = forms.BooleanField( live_migration = forms.BooleanField(
required=False, initial=True, label=_("live migration")) required=False, initial=True, label=_("Live migration"),
help_text=_(
"Live migration is a way of moving virtual machines between "
"hosts with a service interruption of at most some seconds. "
"Please note that it can take very long and cause "
"much network traffic in case of busy machines."))
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
choices = kwargs.pop('choices') choices = kwargs.pop('choices')
...@@ -766,7 +770,7 @@ class VmMigrateForm(forms.Form): ...@@ -766,7 +770,7 @@ class VmMigrateForm(forms.Form):
widget=forms.RadioSelect(), label=_("Node"))) widget=forms.RadioSelect(), label=_("Node")))
class VmStateChangeForm(forms.Form): class VmStateChangeForm(OperationForm):
interrupt = forms.BooleanField(required=False, label=_( interrupt = forms.BooleanField(required=False, label=_(
"Forcibly interrupt all running activities."), "Forcibly interrupt all running activities."),
...@@ -785,25 +789,13 @@ class VmStateChangeForm(forms.Form): ...@@ -785,25 +789,13 @@ class VmStateChangeForm(forms.Form):
self.fields['interrupt'].widget = HiddenInput() self.fields['interrupt'].widget = HiddenInput()
self.fields['new_state'].initial = status self.fields['new_state'].initial = status
@property
def helper(self):
helper = FormHelper(self)
helper.form_tag = False
return helper
class RedeployForm(forms.Form): class RedeployForm(OperationForm):
with_emergency_change_state = forms.BooleanField( with_emergency_change_state = forms.BooleanField(
required=False, initial=True, label=_("use emergency state change")) required=False, initial=True, label=_("use emergency state change"))
@property
def helper(self):
helper = FormHelper(self)
helper.form_tag = False
return helper
class VmCreateDiskForm(forms.Form): class VmCreateDiskForm(OperationForm):
name = forms.CharField(max_length=100, label=_("Name")) name = forms.CharField(max_length=100, label=_("Name"))
size = forms.CharField( size = forms.CharField(
widget=FileSizeWidget, initial=(10 << 30), label=_('Size'), widget=FileSizeWidget, initial=(10 << 30), label=_('Size'),
...@@ -823,14 +815,8 @@ class VmCreateDiskForm(forms.Form): ...@@ -823,14 +815,8 @@ class VmCreateDiskForm(forms.Form):
" GB or MB!")) " GB or MB!"))
return size_in_bytes return size_in_bytes
@property
def helper(self):
helper = FormHelper(self)
helper.form_tag = False
return helper
class VmDiskResizeForm(forms.Form): class VmDiskResizeForm(OperationForm):
size = forms.CharField( size = forms.CharField(
widget=FileSizeWidget, initial=(10 << 30), label=_('Size'), widget=FileSizeWidget, initial=(10 << 30), label=_('Size'),
help_text=_('Size to resize the disk in bytes or with units ' help_text=_('Size to resize the disk in bytes or with units '
...@@ -863,8 +849,7 @@ class VmDiskResizeForm(forms.Form): ...@@ -863,8 +849,7 @@ class VmDiskResizeForm(forms.Form):
@property @property
def helper(self): def helper(self):
helper = FormHelper(self) helper = super(VmDiskResizeForm, self).helper
helper.form_tag = False
if self.disk: if self.disk:
helper.layout = Layout( helper.layout = Layout(
HTML(_("<label>Disk:</label> %s") % escape(self.disk)), HTML(_("<label>Disk:</label> %s") % escape(self.disk)),
...@@ -872,7 +857,7 @@ class VmDiskResizeForm(forms.Form): ...@@ -872,7 +857,7 @@ class VmDiskResizeForm(forms.Form):
return helper return helper
class VmDiskRemoveForm(forms.Form): class VmDiskRemoveForm(OperationForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
choices = kwargs.pop('choices') choices = kwargs.pop('choices')
self.disk = kwargs.pop('default') self.disk = kwargs.pop('default')
...@@ -887,8 +872,7 @@ class VmDiskRemoveForm(forms.Form): ...@@ -887,8 +872,7 @@ class VmDiskRemoveForm(forms.Form):
@property @property
def helper(self): def helper(self):
helper = FormHelper(self) helper = super(VmDiskRemoveForm, self).helper
helper.form_tag = False
if self.disk: if self.disk:
helper.layout = Layout( helper.layout = Layout(
AnyTag( AnyTag(
...@@ -901,16 +885,10 @@ class VmDiskRemoveForm(forms.Form): ...@@ -901,16 +885,10 @@ class VmDiskRemoveForm(forms.Form):
return helper return helper
class VmDownloadDiskForm(forms.Form): class VmDownloadDiskForm(OperationForm):
name = forms.CharField(max_length=100, label=_("Name"), required=False) name = forms.CharField(max_length=100, label=_("Name"), required=False)
url = forms.CharField(label=_('URL'), validators=[URLValidator(), ]) url = forms.CharField(label=_('URL'), validators=[URLValidator(), ])
@property
def helper(self):
helper = FormHelper(self)
helper.form_tag = False
return helper
def clean(self): def clean(self):
cleaned_data = super(VmDownloadDiskForm, self).clean() cleaned_data = super(VmDownloadDiskForm, self).clean()
if not cleaned_data['name']: if not cleaned_data['name']:
...@@ -924,7 +902,7 @@ class VmDownloadDiskForm(forms.Form): ...@@ -924,7 +902,7 @@ class VmDownloadDiskForm(forms.Form):
return cleaned_data return cleaned_data
class VmAddInterfaceForm(forms.Form): class VmAddInterfaceForm(OperationForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
choices = kwargs.pop('choices') choices = kwargs.pop('choices')
super(VmAddInterfaceForm, self).__init__(*args, **kwargs) super(VmAddInterfaceForm, self).__init__(*args, **kwargs)
...@@ -936,11 +914,19 @@ class VmAddInterfaceForm(forms.Form): ...@@ -936,11 +914,19 @@ class VmAddInterfaceForm(forms.Form):
field.empty_label = _('No more networks.') field.empty_label = _('No more networks.')
self.fields['vlan'] = field self.fields['vlan'] = field
@property
def helper(self): class VmDeployForm(OperationForm):
helper = FormHelper(self)
helper.form_tag = False def __init__(self, *args, **kwargs):
return helper choices = kwargs.pop('choices', None)
super(VmDeployForm, self).__init__(*args, **kwargs)
if choices is not None:
self.fields.insert(0, 'node', forms.ModelChoiceField(
queryset=choices, required=False, label=_('Node'), help_text=_(
"Deploy virtual machine to this node "
"(blank allows scheduling automatically).")))
class CircleAuthenticationForm(AuthenticationForm): class CircleAuthenticationForm(AuthenticationForm):
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
<span class="operation-wrapper"> <span class="operation-wrapper">
<a href="{{ op.remove_disk.get_url }}?disk={{d.pk}}" <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 class="btn btn-xs btn-{{ op.remove_disk.effect}} pull-right operation disk-remove-btn
{% if op.resize_disk.disabled %}disabled{% endif %}"> {% if op.remove_disk.disabled %}disabled{% endif %}">
<i class="fa fa-{{ op.remove_disk.icon }}"></i> {% trans "Remove" %} <i class="fa fa-{{ op.remove_disk.icon }}"></i> {% trans "Remove" %}
</a> </a>
</span> </span>
......
...@@ -60,7 +60,7 @@ from ..forms import ( ...@@ -60,7 +60,7 @@ from ..forms import (
VmAddInterfaceForm, VmCreateDiskForm, VmDownloadDiskForm, VmSaveForm, VmAddInterfaceForm, VmCreateDiskForm, VmDownloadDiskForm, VmSaveForm,
VmRenewForm, VmStateChangeForm, VmListSearchForm, VmCustomizeForm, VmRenewForm, VmStateChangeForm, VmListSearchForm, VmCustomizeForm,
TransferOwnershipForm, VmDiskResizeForm, RedeployForm, VmDiskRemoveForm, TransferOwnershipForm, VmDiskResizeForm, RedeployForm, VmDiskRemoveForm,
VmMigrateForm, VmMigrateForm, VmDeployForm,
) )
from ..models import Favourite, Profile from ..models import Favourite, Profile
...@@ -605,7 +605,6 @@ class VmStateChangeView(FormOperationMixin, VmOperationView): ...@@ -605,7 +605,6 @@ class VmStateChangeView(FormOperationMixin, VmOperationView):
op = 'emergency_change_state' op = 'emergency_change_state'
icon = 'legal' icon = 'legal'
effect = 'danger' effect = 'danger'
show_in_toolbar = True
form_class = VmStateChangeForm form_class = VmStateChangeForm
wait_for_result = 0.5 wait_for_result = 0.5
...@@ -628,9 +627,23 @@ class RedeployView(FormOperationMixin, VmOperationView): ...@@ -628,9 +627,23 @@ class RedeployView(FormOperationMixin, VmOperationView):
wait_for_result = 0.5 wait_for_result = 0.5
class VmDeployView(FormOperationMixin, VmOperationView):
op = 'deploy'
icon = 'play'
effect = 'success'
form_class = VmDeployForm
def get_form_kwargs(self):
kwargs = super(VmDeployView, self).get_form_kwargs()
if self.request.user.is_superuser:
online = (n.pk for n in
Node.objects.filter(enabled=True) if n.online)
kwargs['choices'] = Node.objects.filter(pk__in=online)
return kwargs
vm_ops = OrderedDict([ vm_ops = OrderedDict([
('deploy', VmOperationView.factory( ('deploy', VmDeployView),
op='deploy', icon='play', effect='success')),
('wake_up', VmOperationView.factory( ('wake_up', VmOperationView.factory(
op='wake_up', icon='sun-o', effect='success')), op='wake_up', icon='sun-o', effect='success')),
('sleep', VmOperationView.factory( ('sleep', VmOperationView.factory(
......
...@@ -324,10 +324,14 @@ class DeployOperation(InstanceOperation): ...@@ -324,10 +324,14 @@ class DeployOperation(InstanceOperation):
"deployed to node: %(node)s"), "deployed to node: %(node)s"),
node=self.instance.node) node=self.instance.node)
def _operation(self, activity): def _operation(self, activity, node=None):
# Allocate VNC port and host node # Allocate VNC port and host node
self.instance.allocate_vnc_port() self.instance.allocate_vnc_port()
self.instance.allocate_node() if node is not None:
self.instance.node = node
self.instance.save()
else:
self.instance.allocate_node()
# Deploy virtual images # Deploy virtual images
self.instance._deploy_disks(parent_activity=activity) self.instance._deploy_disks(parent_activity=activity)
...@@ -462,8 +466,8 @@ class DestroyOperation(InstanceOperation): ...@@ -462,8 +466,8 @@ class DestroyOperation(InstanceOperation):
class MigrateOperation(RemoteInstanceOperation): class MigrateOperation(RemoteInstanceOperation):
id = 'migrate' id = 'migrate'
name = _("migrate") name = _("migrate")
description = _("Move virtual machine to an other worker node with a few " description = _("Move a running virtual machine to an other worker node "
"seconds of interruption (live migration).") "keeping its full state.")
required_perms = () required_perms = ()
superuser_required = True superuser_required = True
accept_states = ('RUNNING', ) accept_states = ('RUNNING', )
......
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