Commit 8e1635ef by Kálmán Viktor

Merge branch 'master' into feature-pipeline

Conflicts:
	circle/dashboard/static/dashboard/dashboard.css
	circle/dashboard/static/dashboard/vm-details.js
	circle/dashboard/templates/base.html
	circle/dashboard/templates/dashboard/index-vm.html
parents 9bcc0385 ea3039d6
......@@ -538,3 +538,6 @@ SESSION_COOKIE_NAME = "csessid%x" % (((getnode() // 139) ^
(getnode() % 983)) & 0xffff)
MAX_NODE_RAM = get_env_variable("MAX_NODE_RAM", 1024)
# Url to download the client: (e.g. http://circlecloud.org/client/download/)
CLIENT_DOWNLOAD_URL = get_env_variable('CLIENT_DOWNLOAD_URL', 'http://circlecloud.org/client/download/')
......@@ -214,6 +214,14 @@ class ActivityModel(TimeStampedModel):
self.result_data = None if value is None else value.to_dict()
@classmethod
def construct_activity_code(cls, code_suffix, sub_suffix=None):
code = join_activity_code(cls.ACTIVITY_CODE_BASE, code_suffix)
if sub_suffix:
return join_activity_code(code, sub_suffix)
else:
return code
@celery.task()
def compute_cached(method, instance, memcached_seconds,
......@@ -488,7 +496,7 @@ class HumanReadableException(HumanReadableObject, Exception):
"Level should be the name of an attribute of django."
"contrib.messages (and it should be callable with "
"(request, message)). Like 'error', 'warning'.")
else:
elif not hasattr(self, "level"):
self.level = "error"
def send_message(self, request, level=None):
......
......@@ -21,18 +21,22 @@ from django import contrib
from django.contrib.auth.admin import UserAdmin, GroupAdmin
from django.contrib.auth.models import User, Group
from dashboard.models import Profile, GroupProfile
from dashboard.models import Profile, GroupProfile, ConnectCommand
class ProfileInline(contrib.admin.TabularInline):
model = Profile
class CommandInline(contrib.admin.TabularInline):
model = ConnectCommand
class GroupProfileInline(contrib.admin.TabularInline):
model = GroupProfile
UserAdmin.inlines = (ProfileInline, )
UserAdmin.inlines = (ProfileInline, CommandInline, )
GroupAdmin.inlines = (GroupProfileInline, )
contrib.admin.site.unregister(User)
......
import autocomplete_light
from django.contrib.auth.models import User
from django.utils.html import escape
from django.utils.translation import ugettext as _
from .views import AclUpdateView
from .models import Profile
class AclUserAutocomplete(autocomplete_light.AutocompleteGenericBase):
def highlight(field, q, none_wo_match=True):
"""
>>> highlight('<b>Akkount Krokodil', 'kro', False)
u'&lt;b&gt;Akkount <span class="autocomplete-hl">Kro</span>kodil'
"""
if not field:
return None
try:
match = field.lower().index(q.lower())
except ValueError:
match = None
if q and match is not None:
match_end = match + len(q)
return (escape(field[:match])
+ '<span class="autocomplete-hl">'
+ escape(field[match:match_end])
+ '</span>' + escape(field[match_end:]))
elif none_wo_match:
return None
else:
return escape(field)
class AclUserGroupAutocomplete(autocomplete_light.AutocompleteGenericBase):
search_fields = (
('^first_name', 'last_name', 'username', '^email', 'profile__org_id'),
('^name', 'groupprofile__org_id'),
('first_name', 'last_name', 'username', 'email', 'profile__org_id'),
('name', 'groupprofile__org_id'),
)
autocomplete_js_attributes = {'placeholder': _("Name of group or user")}
choice_html_format = u'<span data-value="%s"><span>%s</span> %s</span>'
choice_html_format = (u'<span data-value="%s"><span style="display:none"'
u'>%s</span>%s</span>')
def choice_html(self, choice):
def choice_displayed_text(self, choice):
q = unicode(self.request.GET.get('q', ''))
name = highlight(unicode(choice), q, False)
if isinstance(choice, User):
extra_fields = [highlight(choice.get_full_name(), q, False),
highlight(choice.email, q)]
try:
name = choice.get_full_name()
except AttributeError:
name = _('group')
if name:
name = u'(%s)' % name
extra_fields.append(highlight(choice.profile.org_id, q))
except Profile.DoesNotExist:
pass
return '%s (%s)' % (name, ', '.join(f for f in extra_fields
if f))
else:
return _('%s (group)') % name
def choice_html(self, choice):
return self.choice_html_format % (
self.choice_value(choice), self.choice_label(choice), name)
self.choice_value(choice), self.choice_label(choice),
self.choice_displayed_text(choice))
def choices_for_request(self):
user = self.request.user
self.choices = (AclUpdateView.get_allowed_users(user),
AclUpdateView.get_allowed_groups(user))
return super(AclUserAutocomplete, self).choices_for_request()
return super(AclUserGroupAutocomplete, self).choices_for_request()
def autocomplete_html(self):
html = []
for choice in self.choices_for_request():
html.append(self.choice_html(choice))
if not html:
html = self.empty_html_format % _('no matches found').capitalize()
return self.autocomplete_html_format % ''.join(html)
class AclUserAutocomplete(AclUserGroupAutocomplete):
def choices_for_request(self):
user = self.request.user
self.choices = (AclUpdateView.get_allowed_users(user), )
return super(AclUserGroupAutocomplete, self).choices_for_request()
autocomplete_light.register(AclUserGroupAutocomplete)
autocomplete_light.register(AclUserAutocomplete)
......@@ -1383,7 +1383,6 @@
"time_of_suspend": null,
"ram_size": 200,
"priority": 10,
"active_since": null,
"template": null,
"access_method": "nx",
"lease": 1,
......@@ -1413,7 +1412,6 @@
"time_of_suspend": null,
"ram_size": 200,
"priority": 10,
"active_since": null,
"template": null,
"access_method": "nx",
"lease": 1,
......
......@@ -54,7 +54,9 @@ from .models import Profile, GroupProfile
from circle.settings.base import LANGUAGES, MAX_NODE_RAM
from django.utils.translation import string_concat
from .virtvalidator import domain_validator
from .validators import domain_validator
from dashboard.models import ConnectCommand
LANGUAGES_WITH_CODE = ((l[0], string_concat(l[1], " (", l[0], ")"))
for l in LANGUAGES)
......@@ -141,6 +143,8 @@ class VmCustomizeForm(forms.Form):
self.template = kwargs.pop("template", None)
super(VmCustomizeForm, self).__init__(*args, **kwargs)
if self.user.has_perm("vm.set_resources"):
self.allowed_fields = tuple(self.fields.keys())
# set displayed disk and network list
self.fields['disks'].queryset = self.template.disks.all()
self.fields['networks'].queryset = Vlan.get_objects_with_level(
......@@ -156,10 +160,29 @@ class VmCustomizeForm(forms.Form):
self.initial['cpu_count'] = self.template.num_cores
self.initial['ram_size'] = self.template.ram_size
else:
self.allowed_fields = ("name", "template", "customized", )
# initial name and template pk
self.initial['name'] = self.template.name
self.initial['template'] = self.template.pk
self.initial['customized'] = self.template.pk
self.initial['customized'] = True
def _clean_fields(self):
for name, field in self.fields.items():
if name in self.allowed_fields:
value = field.widget.value_from_datadict(
self.data, self.files, self.add_prefix(name))
try:
value = field.clean(value)
self.cleaned_data[name] = value
if hasattr(self, 'clean_%s' % name):
value = getattr(self, 'clean_%s' % name)()
self.cleaned_data[name] = value
except ValidationError as e:
self._errors[name] = self.error_class(e.messages)
if name in self.cleaned_data:
del self.cleaned_data[name]
class GroupCreateForm(forms.ModelForm):
......@@ -176,7 +199,14 @@ class GroupCreateForm(forms.ModelForm):
self.fields['org_id'] = forms.ChoiceField(
# TRANSLATORS: directory like in LDAP
choices=choices, required=False, label=_('Directory identifier'))
if not new_groups:
if new_groups:
self.fields['org_id'].help_text = _(
"If you select an item here, the members of this directory "
"group will be automatically added to the group at the time "
"they log in. Please note that other users (those with "
"permissions like yours) may also automatically become a "
"group co-owner).")
else:
self.fields['org_id'].widget = HiddenInput()
def save(self, commit=True):
......@@ -451,7 +481,7 @@ class TemplateForm(forms.ModelForm):
else:
self.allowed_fields = (
'name', 'access_method', 'description', 'system', 'tags',
'arch', 'lease')
'arch', 'lease', 'has_agent')
if (self.user.has_perm('vm.change_template_resources')
or not self.instance.pk):
self.allowed_fields += tuple(set(self.fields.keys()) -
......@@ -1025,9 +1055,29 @@ class UserCreationForm(OrgUserCreationForm):
return user
class AclUserAddForm(forms.Form):
class AclUserOrGroupAddForm(forms.Form):
name = forms.CharField(widget=autocomplete_light.TextWidget(
'AclUserAutocomplete', attrs={'class': 'form-control'}))
'AclUserGroupAutocomplete',
autocomplete_js_attributes={'placeholder': _("Name of group or user")},
attrs={'class': 'form-control'}))
class TransferOwnershipForm(forms.Form):
name = forms.CharField(
widget=autocomplete_light.TextWidget(
'AclUserAutocomplete',
autocomplete_js_attributes={"placeholder": _("Name of user")},
attrs={'class': 'form-control'}),
label=_("E-mail address or identifier of user"))
class AddGroupMemberForm(forms.Form):
new_member = forms.CharField(
widget=autocomplete_light.TextWidget(
'AclUserAutocomplete',
autocomplete_js_attributes={"placeholder": _("Name of user")},
attrs={'class': 'form-control'}),
label=_("E-mail address or identifier of user"))
class UserKeyForm(forms.ModelForm):
......@@ -1057,6 +1107,22 @@ class UserKeyForm(forms.ModelForm):
return super(UserKeyForm, self).clean()
class ConnectCommandForm(forms.ModelForm):
class Meta:
fields = ('name', 'access_method', 'template')
model = ConnectCommand
def __init__(self, *args, **kwargs):
self.user = kwargs.pop("user")
super(ConnectCommandForm, self).__init__(*args, **kwargs)
def clean(self):
if self.user:
self.instance.user = self.user
return super(ConnectCommandForm, self).clean()
class TraitsForm(forms.ModelForm):
class Meta:
......@@ -1174,7 +1240,12 @@ class VmListSearchForm(forms.Form):
}))
stype = forms.ChoiceField(vm_search_choices, widget=forms.Select(attrs={
'class': "btn btn-default input-tags",
'class': "btn btn-default form-control input-tags",
'style': "min-width: 80px;",
}))
include_deleted = forms.BooleanField(widget=forms.CheckboxInput(attrs={
'id': "vm-list-search-checkbox",
}))
def __init__(self, *args, **kwargs):
......@@ -1184,3 +1255,22 @@ class VmListSearchForm(forms.Form):
data = self.data.copy()
data['stype'] = "all"
self.data = data
class TemplateListSearchForm(forms.Form):
s = forms.CharField(widget=forms.TextInput(attrs={
'class': "form-control input-tags",
'placeholder': _("Search...")
}))
stype = forms.ChoiceField(vm_search_choices, widget=forms.Select(attrs={
'class': "btn btn-default input-tags",
}))
def __init__(self, *args, **kwargs):
super(TemplateListSearchForm, self).__init__(*args, **kwargs)
# set initial value, otherwise it would be overwritten by request.GET
if not self.data.get("stype"):
data = self.data.copy()
data['stype'] = "owned"
self.data = data
# -*- 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):
# Adding model 'ConnectCommand'
db.create_table(u'dashboard_connectcommand', (
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='command_set', to=orm['auth.User'])),
('access_method', self.gf('django.db.models.fields.CharField')(max_length=10)),
('application', self.gf('django.db.models.fields.CharField')(max_length='128')),
('template', self.gf('django.db.models.fields.CharField')(max_length=256, null=True, blank=True)),
))
db.send_create_signal(u'dashboard', ['ConnectCommand'])
def backwards(self, orm):
# Deleting model 'ConnectCommand'
db.delete_table(u'dashboard_connectcommand')
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'dashboard.connectcommand': {
'Meta': {'object_name': 'ConnectCommand'},
'access_method': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
'application': ('django.db.models.fields.CharField', [], {'max_length': "'128'"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'template': ('django.db.models.fields.CharField', [], {'max_length': '256', 'null': 'True', 'blank': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'command_set'", 'to': u"orm['auth.User']"})
},
u'dashboard.favourite': {
'Meta': {'object_name': 'Favourite'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'instance': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['vm.Instance']"}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"})
},
u'dashboard.futuremember': {
'Meta': {'unique_together': "(('org_id', 'group'),)", 'object_name': 'FutureMember'},
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.Group']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'org_id': ('django.db.models.fields.CharField', [], {'max_length': '64'})
},
u'dashboard.groupprofile': {
'Meta': {'object_name': 'GroupProfile'},
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'group': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.Group']", 'unique': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'org_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'unique': 'True', 'null': 'True', 'blank': 'True'})
},
u'dashboard.notification': {
'Meta': {'ordering': "['-created']", 'object_name': 'Notification'},
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'message_data': ('jsonfield.fields.JSONField', [], {'null': 'True'}),
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
'status': ('model_utils.fields.StatusField', [], {'default': "'new'", 'max_length': '100', u'no_check_for_status': 'True'}),
'subject_data': ('jsonfield.fields.JSONField', [], {'null': 'True'}),
'to': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
'valid_until': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'})
},
u'dashboard.profile': {
'Meta': {'object_name': 'Profile'},
'disk_quota': ('sizefield.models.FileSizeField', [], {'default': '2147483648'}),
'email_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'instance_limit': ('django.db.models.fields.IntegerField', [], {'default': '5'}),
'org_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'preferred_language': ('django.db.models.fields.CharField', [], {'default': "'en'", 'max_length': '32'}),
'smb_password': ('django.db.models.fields.CharField', [], {'default': "u'uUmt7R9peX'", 'max_length': '20'}),
'use_gravatar': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'user': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.User']", 'unique': 'True'})
},
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.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.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'storage.datastore': {
'Meta': {'ordering': "[u'name']", 'object_name': 'DataStore'},
'hostname': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200'})
},
u'storage.disk': {
'Meta': {'ordering': "[u'name']", 'object_name': 'Disk'},
'base': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'derivatives'", 'null': 'True', 'to': u"orm['storage.Disk']"}),
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
'datastore': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['storage.DataStore']"}),
'destroyed': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
'dev_num': ('django.db.models.fields.CharField', [], {'default': "u'a'", 'max_length': '1'}),
'filename': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '256'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_ready': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'size': ('sizefield.models.FileSizeField', [], {'default': 'None', 'null': 'True'}),
'type': ('django.db.models.fields.CharField', [], {'max_length': '10'})
},
u'vm.instance': {
'Meta': {'ordering': "(u'pk',)", 'object_name': 'Instance'},
'access_method': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
'active_since': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'arch': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
'boot_menu': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'destroyed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'disks': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "u'instance_set'", 'symmetrical': 'False', 'to': u"orm['storage.Disk']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_base': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'lease': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['vm.Lease']"}),
'max_ram_size': ('django.db.models.fields.IntegerField', [], {}),
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'node': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'instance_set'", 'null': 'True', 'to': u"orm['vm.Node']"}),
'num_cores': ('django.db.models.fields.IntegerField', [], {}),
'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
'priority': ('django.db.models.fields.IntegerField', [], {}),
'pw': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
'ram_size': ('django.db.models.fields.IntegerField', [], {}),
'raw_data': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'req_traits': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['vm.Trait']", 'symmetrical': 'False', 'blank': 'True'}),
'status': ('model_utils.fields.StatusField', [], {'default': "u'NOSTATE'", 'max_length': '100', u'no_check_for_status': 'True'}),
'status_changed': ('model_utils.fields.MonitorField', [], {'default': 'datetime.datetime.now', u'monitor': "u'status'"}),
'system': ('django.db.models.fields.TextField', [], {}),
'template': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'instance_set'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['vm.InstanceTemplate']"}),
'time_of_delete': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
'time_of_suspend': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
'vnc_port': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'})
},
u'vm.instancetemplate': {
'Meta': {'ordering': "(u'name',)", 'object_name': 'InstanceTemplate'},
'access_method': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
'arch': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
'boot_menu': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'disks': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "u'template_set'", 'symmetrical': 'False', 'to': u"orm['storage.Disk']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'lease': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['vm.Lease']"}),
'max_ram_size': ('django.db.models.fields.IntegerField', [], {}),
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'num_cores': ('django.db.models.fields.IntegerField', [], {}),
'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['vm.InstanceTemplate']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}),
'priority': ('django.db.models.fields.IntegerField', [], {}),
'ram_size': ('django.db.models.fields.IntegerField', [], {}),
'raw_data': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'req_traits': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['vm.Trait']", 'symmetrical': 'False', 'blank': 'True'}),
'system': ('django.db.models.fields.TextField', [], {})
},
u'vm.lease': {
'Meta': {'ordering': "[u'name']", 'object_name': 'Lease'},
'delete_interval_seconds': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'suspend_interval_seconds': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
},
u'vm.node': {
'Meta': {'ordering': "(u'-enabled', u'normalized_name')", 'object_name': 'Node'},
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'host': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['firewall.Host']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '50'}),
'normalized_name': ('common.models.HumanSortField', [], {'default': "''", 'maximum_number_length': '4', 'max_length': '100', 'monitor': "u'name'", 'blank': 'True'}),
'overcommit': ('django.db.models.fields.FloatField', [], {'default': '1.0'}),
'priority': ('django.db.models.fields.IntegerField', [], {}),
'traits': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['vm.Trait']", 'symmetrical': 'False', 'blank': 'True'})
},
u'vm.trait': {
'Meta': {'object_name': 'Trait'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
}
}
complete_apps = ['dashboard']
\ No newline at end of file
# -*- 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):
# Deleting field 'ConnectCommand.application'
db.delete_column(u'dashboard_connectcommand', 'application')
# Adding field 'ConnectCommand.name'
db.add_column(u'dashboard_connectcommand', 'name',
self.gf('django.db.models.fields.CharField')(default='szia megint', max_length='128'),
keep_default=False)
def backwards(self, orm):
# Adding field 'ConnectCommand.application'
db.add_column(u'dashboard_connectcommand', 'application',
self.gf('django.db.models.fields.CharField')(default='szia', max_length='128'),
keep_default=False)
# Deleting field 'ConnectCommand.name'
db.delete_column(u'dashboard_connectcommand', 'name')
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'dashboard.connectcommand': {
'Meta': {'object_name': 'ConnectCommand'},
'access_method': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': "'128'"}),
'template': ('django.db.models.fields.CharField', [], {'max_length': '256', 'null': 'True', 'blank': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'command_set'", 'to': u"orm['auth.User']"})
},
u'dashboard.favourite': {
'Meta': {'object_name': 'Favourite'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'instance': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['vm.Instance']"}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"})
},
u'dashboard.futuremember': {
'Meta': {'unique_together': "(('org_id', 'group'),)", 'object_name': 'FutureMember'},
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.Group']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'org_id': ('django.db.models.fields.CharField', [], {'max_length': '64'})
},
u'dashboard.groupprofile': {
'Meta': {'object_name': 'GroupProfile'},
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'group': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.Group']", 'unique': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'org_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'unique': 'True', 'null': 'True', 'blank': 'True'})
},
u'dashboard.notification': {
'Meta': {'ordering': "['-created']", 'object_name': 'Notification'},
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'message_data': ('jsonfield.fields.JSONField', [], {'null': 'True'}),
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
'status': ('model_utils.fields.StatusField', [], {'default': "'new'", 'max_length': '100', u'no_check_for_status': 'True'}),
'subject_data': ('jsonfield.fields.JSONField', [], {'null': 'True'}),
'to': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
'valid_until': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'})
},
u'dashboard.profile': {
'Meta': {'object_name': 'Profile'},
'disk_quota': ('sizefield.models.FileSizeField', [], {'default': '2147483648'}),
'email_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'instance_limit': ('django.db.models.fields.IntegerField', [], {'default': '5'}),
'org_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'preferred_language': ('django.db.models.fields.CharField', [], {'default': "'en'", 'max_length': '32'}),
'smb_password': ('django.db.models.fields.CharField', [], {'default': "u'NRERukxe3Z'", 'max_length': '20'}),
'use_gravatar': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'user': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.User']", 'unique': 'True'})
},
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.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.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'storage.datastore': {
'Meta': {'ordering': "[u'name']", 'object_name': 'DataStore'},
'hostname': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200'})
},
u'storage.disk': {
'Meta': {'ordering': "[u'name']", 'object_name': 'Disk'},
'base': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'derivatives'", 'null': 'True', 'to': u"orm['storage.Disk']"}),
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
'datastore': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['storage.DataStore']"}),
'destroyed': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
'dev_num': ('django.db.models.fields.CharField', [], {'default': "u'a'", 'max_length': '1'}),
'filename': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '256'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_ready': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'size': ('sizefield.models.FileSizeField', [], {'default': 'None', 'null': 'True'}),
'type': ('django.db.models.fields.CharField', [], {'max_length': '10'})
},
u'vm.instance': {
'Meta': {'ordering': "(u'pk',)", 'object_name': 'Instance'},
'access_method': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
'active_since': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'arch': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
'boot_menu': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'destroyed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'disks': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "u'instance_set'", 'symmetrical': 'False', 'to': u"orm['storage.Disk']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_base': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'lease': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['vm.Lease']"}),
'max_ram_size': ('django.db.models.fields.IntegerField', [], {}),
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'node': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'instance_set'", 'null': 'True', 'to': u"orm['vm.Node']"}),
'num_cores': ('django.db.models.fields.IntegerField', [], {}),
'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
'priority': ('django.db.models.fields.IntegerField', [], {}),
'pw': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
'ram_size': ('django.db.models.fields.IntegerField', [], {}),
'raw_data': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'req_traits': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['vm.Trait']", 'symmetrical': 'False', 'blank': 'True'}),
'status': ('model_utils.fields.StatusField', [], {'default': "u'NOSTATE'", 'max_length': '100', u'no_check_for_status': 'True'}),
'status_changed': ('model_utils.fields.MonitorField', [], {'default': 'datetime.datetime.now', u'monitor': "u'status'"}),
'system': ('django.db.models.fields.TextField', [], {}),
'template': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'instance_set'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['vm.InstanceTemplate']"}),
'time_of_delete': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
'time_of_suspend': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
'vnc_port': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'})
},
u'vm.instancetemplate': {
'Meta': {'ordering': "(u'name',)", 'object_name': 'InstanceTemplate'},
'access_method': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
'arch': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
'boot_menu': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'disks': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "u'template_set'", 'symmetrical': 'False', 'to': u"orm['storage.Disk']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'lease': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['vm.Lease']"}),
'max_ram_size': ('django.db.models.fields.IntegerField', [], {}),
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'num_cores': ('django.db.models.fields.IntegerField', [], {}),
'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['vm.InstanceTemplate']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}),
'priority': ('django.db.models.fields.IntegerField', [], {}),
'ram_size': ('django.db.models.fields.IntegerField', [], {}),
'raw_data': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'req_traits': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['vm.Trait']", 'symmetrical': 'False', 'blank': 'True'}),
'system': ('django.db.models.fields.TextField', [], {})
},
u'vm.lease': {
'Meta': {'ordering': "[u'name']", 'object_name': 'Lease'},
'delete_interval_seconds': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'suspend_interval_seconds': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
},
u'vm.node': {
'Meta': {'ordering': "(u'-enabled', u'normalized_name')", 'object_name': 'Node'},
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'host': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['firewall.Host']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '50'}),
'normalized_name': ('common.models.HumanSortField', [], {'default': "''", 'maximum_number_length': '4', 'max_length': '100', 'monitor': "u'name'", 'blank': 'True'}),
'overcommit': ('django.db.models.fields.FloatField', [], {'default': '1.0'}),
'priority': ('django.db.models.fields.IntegerField', [], {}),
'traits': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['vm.Trait']", 'symmetrical': 'False', 'blank': 'True'})
},
u'vm.trait': {
'Meta': {'object_name': 'Trait'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
}
}
complete_apps = ['dashboard']
\ No newline at end of file
# -*- coding: utf-8 -*-
from south.utils import datetime_utils as datetime
from south.db import db
from south.v2 import DataMigration
from django.db import models
class Migration(DataMigration):
def forwards(self, orm):
"Re-save blank Profile.org_id to be saved as NULL"
for i in orm.Profile.objects.filter(org_id=""):
i.save()
# fix default passwords set in migration 0010
f = [f for f in orm.Profile._meta.fields if f.name == 'smb_password'][0]
for i in orm.Profile.objects.filter(smb_password="asdasd"):
i.smb_password = f.get_default()
i.save()
def backwards(self, orm):
"Write your backwards methods here."
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'dashboard.connectcommand': {
'Meta': {'object_name': 'ConnectCommand'},
'access_method': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': "'128'"}),
'template': ('django.db.models.fields.CharField', [], {'max_length': '256', 'null': 'True', 'blank': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'command_set'", 'to': u"orm['auth.User']"})
},
u'dashboard.favourite': {
'Meta': {'object_name': 'Favourite'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'instance': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['vm.Instance']"}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"})
},
u'dashboard.futuremember': {
'Meta': {'unique_together': "(('org_id', 'group'),)", 'object_name': 'FutureMember'},
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.Group']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'org_id': ('django.db.models.fields.CharField', [], {'max_length': '64'})
},
u'dashboard.groupprofile': {
'Meta': {'object_name': 'GroupProfile'},
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'group': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.Group']", 'unique': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'org_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'unique': 'True', 'null': 'True', 'blank': 'True'})
},
u'dashboard.notification': {
'Meta': {'ordering': "['-created']", 'object_name': 'Notification'},
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'message_data': ('jsonfield.fields.JSONField', [], {'null': 'True'}),
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
'status': ('model_utils.fields.StatusField', [], {'default': "'new'", 'max_length': '100', u'no_check_for_status': 'True'}),
'subject_data': ('jsonfield.fields.JSONField', [], {'null': 'True'}),
'to': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
'valid_until': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'})
},
u'dashboard.profile': {
'Meta': {'object_name': 'Profile'},
'disk_quota': ('sizefield.models.FileSizeField', [], {'default': '2147483648'}),
'email_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'instance_limit': ('django.db.models.fields.IntegerField', [], {'default': '5'}),
'org_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'preferred_language': ('django.db.models.fields.CharField', [], {'default': "'en'", 'max_length': '32'}),
'smb_password': ('django.db.models.fields.CharField', [], {'default': "u'5DP9uNZdKs'", 'max_length': '20'}),
'use_gravatar': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'user': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.User']", 'unique': 'True'})
},
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.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.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'storage.datastore': {
'Meta': {'ordering': "[u'name']", 'object_name': 'DataStore'},
'hostname': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200'})
},
u'storage.disk': {
'Meta': {'ordering': "[u'name']", 'object_name': 'Disk'},
'base': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'derivatives'", 'null': 'True', 'to': u"orm['storage.Disk']"}),
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
'datastore': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['storage.DataStore']"}),
'destroyed': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
'dev_num': ('django.db.models.fields.CharField', [], {'default': "u'a'", 'max_length': '1'}),
'filename': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '256'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_ready': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'size': ('sizefield.models.FileSizeField', [], {'default': 'None', 'null': 'True'}),
'type': ('django.db.models.fields.CharField', [], {'max_length': '10'})
},
u'vm.instance': {
'Meta': {'ordering': "(u'pk',)", 'object_name': 'Instance'},
'access_method': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
'active_since': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'arch': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
'boot_menu': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'destroyed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'disks': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "u'instance_set'", 'symmetrical': 'False', 'to': u"orm['storage.Disk']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_base': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'lease': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['vm.Lease']"}),
'max_ram_size': ('django.db.models.fields.IntegerField', [], {}),
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'node': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'instance_set'", 'null': 'True', 'to': u"orm['vm.Node']"}),
'num_cores': ('django.db.models.fields.IntegerField', [], {}),
'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
'priority': ('django.db.models.fields.IntegerField', [], {}),
'pw': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
'ram_size': ('django.db.models.fields.IntegerField', [], {}),
'raw_data': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'req_traits': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['vm.Trait']", 'symmetrical': 'False', 'blank': 'True'}),
'status': ('model_utils.fields.StatusField', [], {'default': "u'NOSTATE'", 'max_length': '100', u'no_check_for_status': 'True'}),
'status_changed': ('model_utils.fields.MonitorField', [], {'default': 'datetime.datetime.now', u'monitor': "u'status'"}),
'system': ('django.db.models.fields.TextField', [], {}),
'template': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'instance_set'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['vm.InstanceTemplate']"}),
'time_of_delete': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
'time_of_suspend': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
'vnc_port': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'})
},
u'vm.instancetemplate': {
'Meta': {'ordering': "(u'name',)", 'object_name': 'InstanceTemplate'},
'access_method': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
'arch': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
'boot_menu': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'disks': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "u'template_set'", 'symmetrical': 'False', 'to': u"orm['storage.Disk']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'lease': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['vm.Lease']"}),
'max_ram_size': ('django.db.models.fields.IntegerField', [], {}),
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'num_cores': ('django.db.models.fields.IntegerField', [], {}),
'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['vm.InstanceTemplate']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}),
'priority': ('django.db.models.fields.IntegerField', [], {}),
'ram_size': ('django.db.models.fields.IntegerField', [], {}),
'raw_data': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'req_traits': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['vm.Trait']", 'symmetrical': 'False', 'blank': 'True'}),
'system': ('django.db.models.fields.TextField', [], {})
},
u'vm.lease': {
'Meta': {'ordering': "[u'name']", 'object_name': 'Lease'},
'delete_interval_seconds': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'suspend_interval_seconds': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
},
u'vm.node': {
'Meta': {'ordering': "(u'-enabled', u'normalized_name')", 'object_name': 'Node'},
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'host': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['firewall.Host']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '50'}),
'normalized_name': ('common.models.HumanSortField', [], {'default': "''", 'maximum_number_length': '4', 'max_length': '100', 'monitor': "u'name'", 'blank': 'True'}),
'overcommit': ('django.db.models.fields.FloatField', [], {'default': '1.0'}),
'priority': ('django.db.models.fields.IntegerField', [], {}),
'traits': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['vm.Trait']", 'symmetrical': 'False', 'blank': 'True'})
},
u'vm.trait': {
'Meta': {'object_name': 'Trait'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
}
}
complete_apps = ['dashboard']
symmetrical = True
......@@ -46,8 +46,10 @@ from acl.models import AclBase
from common.models import HumanReadableObject, create_readable, Encoder
from vm.tasks.agent_tasks import add_keys, del_keys
from vm.models.instance import ACCESS_METHODS
from .store_api import Store, NoStoreException, NotOkException
from .store_api import Store, NoStoreException, NotOkException, Timeout
from .validators import connect_command_template_validator
logger = getLogger(__name__)
......@@ -100,6 +102,25 @@ class Notification(TimeStampedModel):
self.message_data = None if value is None else value.to_dict()
class ConnectCommand(Model):
user = ForeignKey(User, related_name='command_set')
access_method = CharField(max_length=10, choices=ACCESS_METHODS,
verbose_name=_('access method'),
help_text=_('Type of the remote access method.'))
name = CharField(max_length="128", verbose_name=_('name'), blank=False,
help_text=_("Name of your custom command."))
template = CharField(blank=True, null=True, max_length=256,
verbose_name=_('command template'),
help_text=_('Template for connection command string. '
'Available parameters are: '
'username, password, '
'host, port.'),
validators=[connect_command_template_validator])
def __unicode__(self):
return self.template
class Profile(Model):
user = OneToOneField(User)
preferred_language = CharField(verbose_name=_('preferred language'),
......@@ -129,6 +150,25 @@ class Profile(Model):
default=2048 * 1024 * 1024,
help_text=_('Disk quota in mebibytes.'))
def get_connect_commands(self, instance, use_ipv6=False):
""" Generate connection command based on template."""
single_command = instance.get_connect_command(use_ipv6)
if single_command: # can we even connect to that VM
commands = self.user.command_set.filter(
access_method=instance.access_method)
if commands.count() < 1:
return [single_command]
else:
return [
command.template % {
'port': instance.get_connect_port(use_ipv6=use_ipv6),
'host': instance.get_connect_host(use_ipv6=use_ipv6),
'password': instance.pw,
'username': 'cloud',
} for command in commands]
else:
return []
def notify(self, subject, template, context=None, valid_until=None,
**kwargs):
if context is not None:
......@@ -161,6 +201,11 @@ class Profile(Model):
def __unicode__(self):
return self.get_display_name()
def save(self, *args, **kwargs):
if self.org_id == "":
self.org_id = None
super(Profile, self).save(*args, **kwargs)
class Meta:
permissions = (
('use_autocomplete', _('Can use autocomplete.')),
......@@ -216,7 +261,7 @@ def get_or_create_profile(self):
Group.profile = property(get_or_create_profile)
def create_profile(sender, user, request, **kwargs):
def create_profile(user):
if not user.pk:
return False
profile, created = Profile.objects.get_or_create(user=user)
......@@ -227,7 +272,11 @@ def create_profile(sender, user, request, **kwargs):
logger.exception("Can't create user %s", unicode(user))
return created
user_logged_in.connect(create_profile)
def create_profile_hook(sender, user, request, **kwargs):
return create_profile(user)
user_logged_in.connect(create_profile_hook)
if hasattr(settings, 'SAML_ORG_ID_ATTRIBUTE'):
logger.debug("Register save_org_id to djangosaml2 pre_user_save")
......@@ -301,7 +350,7 @@ def update_store_profile(sender, **kwargs):
profile.disk_quota)
except NoStoreException:
logger.debug("Store is not available.")
except NotOkException:
except (NotOkException, Timeout):
logger.critical("Store is not accepting connections.")
......
......@@ -591,11 +591,15 @@ footer a, footer a:hover, footer a:visited {
width: 100px;
}
#group-detail-user-table tr:last-child td:nth-child(2) {
text-align: left;
}
#group-detail-perm-header {
margin-top: 25px;
}
textarea[name="list-new-namelist"] {
textarea[name="new_members"] {
max-width: 500px;
min-height: 80px;
margin-bottom: 10px;
......@@ -654,7 +658,8 @@ textarea[name="list-new-namelist"] {
width: 130px;
}
#vm-details-connection-string-copy {
.vm-details-connection-string-copy,
#vm-details-pw-show {
cursor: pointer;
}
......@@ -681,10 +686,9 @@ textarea[name="list-new-namelist"] {
max-width: 200px;
}
#dashboard-vm-details-connect-command {
.dashboard-vm-details-connect-command {
/* for mobile view */
margin-bottom: 20px;
}
#store-list-list {
......@@ -868,6 +872,12 @@ textarea[name="list-new-namelist"] {
padding: 5px 0px;
}
#profile-key-list-table td:last-child, #profile-key-list-table th:last-child,
#profile-command-list-table td:last-child, #profile-command-list-table th:last-child,
#profile-command-list-table td:nth-child(2), #profile-command-list-table th:nth-child(2) {
text-align: center;
vertical-align: middle;
}
#vm-list-table .migrating-icon {
-webkit-animation: passing 2s linear infinite;
......@@ -982,3 +992,26 @@ textarea[name="list-new-namelist"] {
.slider {
width: 100%;
}
#vm-list-search-checkbox {
margin-top: -1px;
display: inline-block;
vertical-align: middle;
}
#vm-list-search-checkbox-span {
cursor: pointer
}
#vm-activity-state {
margin-bottom: 15px;
}
.autocomplete-hl {
color: #b20000;
font-weight: bold;
}
.hilight .autocomplete-hl {
color: orange;
}
......@@ -244,7 +244,7 @@ $(function () {
var search_result = [];
var html = '';
for(var i in my_vms) {
if(my_vms[i].name.indexOf(input) != -1) {
if(my_vms[i].name.indexOf(input) != -1 || my_vms[i].host.indexOf(input) != -1) {
search_result.push(my_vms[i]);
}
}
......@@ -383,6 +383,19 @@ $(function () {
$('.notification-messages').load("/dashboard/notifications/");
$('#notification-button a span[class*="badge-pulse"]').remove();
});
/* on the client confirmation button fire the clientInstalledAction */
$(document).on("click", "#client-check-button", function(event) {
var connectUri = $('#connect-uri').val();
clientInstalledAction(connectUri);
return false;
});
$("#dashboard-vm-details-connect-button").click(function(event) {
var connectUri = $(this).attr("href");
clientInstalledAction(connectUri);
return false;
});
});
function generateVmHTML(pk, name, host, icon, _status, fav, is_last) {
......@@ -591,6 +604,12 @@ function addModalConfirmation(func, data) {
});
}
function clientInstalledAction(location) {
setCookie('downloaded_client', true, 365 * 24 * 60 * 60, "/");
window.location.href = location;
$('#confirmation-modal').modal("hide");
}
// for AJAX calls
/**
* Getter for user cookies
......@@ -613,9 +632,25 @@ function getCookie(name) {
return cookieValue;
}
function setCookie(name, value, seconds, path) {
if (seconds!=null) {
var today = new Date();
var expire = new Date();
expire.setTime(today.getTime() + seconds);
}
document.cookie = name+"="+escape(value)+"; expires="+expire.toUTCString()+"; path="+path;
}
/* no js compatibility */
function noJS() {
$('.no-js-hidden').show();
$('.js-hidden').hide();
}
function getParameterByName(name) {
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
results = regex.exec(location.search);
return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}
......@@ -39,6 +39,7 @@ $(function() {
$(".template-list-table thead th").css("cursor", "pointer");
$(".template-list-table th a").on("click", function(event) {
if(!$(this).closest("th").data("sort")) return true;
event.preventDefault();
});
});
......
......@@ -222,6 +222,8 @@ function vmCustomizeLoaded() {
$(this).find("i").prop("class", "fa fa-spinner fa-spin");
if($("#create-modal")) return true;
$.ajax({
url: '/dashboard/vm/create/',
headers: {"X-CSRFToken": getCookie('csrftoken')},
......
......@@ -106,19 +106,20 @@ $(function() {
$("#vm-details-pw-show").click(function() {
var input = $(this).parent("div").children("input");
var eye = $(this).children("#vm-details-pw-eye");
var span = $(this);
eye.tooltip("destroy");
span.tooltip("destroy")
if(eye.hasClass("fa-eye")) {
eye.removeClass("fa-eye").addClass("fa-eye-slash");
input.prop("type", "text");
input.focus();
eye.prop("title", "Hide password");
input.select();
span.prop("title", gettext("Hide password"));
} else {
eye.removeClass("fa-eye-slash").addClass("fa-eye");
input.prop("type", "password");
eye.prop("title", "Show password");
span.prop("title", gettext("Show password"));
}
eye.tooltip();
span.tooltip();
});
/* change password confirmation */
......@@ -199,7 +200,7 @@ $(function() {
$("#vm-details-h1-name, .vm-details-rename-button").click(function() {
$("#vm-details-h1-name").hide();
$("#vm-details-rename").css('display', 'inline');
$("#vm-details-rename-name").focus();
$("#vm-details-rename-name").select();
return false;
});
......@@ -207,7 +208,7 @@ $(function() {
$(".vm-details-home-edit-name-click").click(function() {
$(".vm-details-home-edit-name-click").hide();
$("#vm-details-home-rename").show();
$("input", $("#vm-details-home-rename")).focus();
$("input", $("#vm-details-home-rename")).select();
return false;
});
......@@ -307,8 +308,8 @@ $(function() {
});
// select connection string
$("#vm-details-connection-string-copy").click(function() {
$("#vm-details-connection-string").focus();
$(".vm-details-connection-string-copy").click(function() {
$(this).parent("div").find("input").select();
});
$("a.operation-password_reset").click(function() {
......@@ -378,8 +379,14 @@ function checkNewActivity(runs) {
}
$("#vm-details-state span").html(data.human_readable_status.toUpperCase());
if(data.status == "RUNNING") {
if(data['connect_uri']) {
$("#dashboard-vm-details-connect-button").removeClass('disabled');
}
$("[data-target=#_console]").attr("data-toggle", "pill").attr("href", "#console").parent("li").removeClass("disabled");
} else {
if(data['connect_uri']) {
$("#dashboard-vm-details-connect-button").addClass('disabled');
}
$("[data-target=#_console]").attr("data-toggle", "_pill").attr("href", "#").parent("li").addClass("disabled");
}
......
......@@ -163,9 +163,10 @@ $(function() {
$(this).find('input[type="radio"]').prop("checked", true);
});
if(checkStatusUpdate()) {
if(checkStatusUpdate() || $("#vm-list-table tbody tr").length >= 100) {
updateStatuses(1);
}
});
......@@ -178,6 +179,7 @@ function checkStatusUpdate() {
function updateStatuses(runs) {
var include_deleted = getParameterByName("include_deleted");
$.get("/dashboard/vm/list/?compact", function(result) {
$("#vm-list-table tbody tr").each(function() {
vm = $(this).data("vm-pk");
......@@ -203,6 +205,7 @@ function updateStatuses(runs) {
$(this).find(".node").text(result[vm].node);
}
} else {
if(!include_deleted)
$(this).remove();
}
});
......
......@@ -7,6 +7,7 @@ from datetime import datetime
from django.http import Http404
from django.conf import settings
from requests import get, post, codes
from requests.exceptions import Timeout # noqa
from sizefield.utils import filesizeformat
logger = logging.getLogger(__name__)
......
......@@ -25,6 +25,7 @@ from django_tables2.columns import (TemplateColumn, Column, BooleanColumn,
from vm.models import Node, InstanceTemplate, Lease
from django.utils.translation import ugettext_lazy as _
from django_sshkey.models import UserKey
from dashboard.models import ConnectCommand
class NodeListTable(Table):
......@@ -146,13 +147,11 @@ class TemplateListTable(Table):
template_name="dashboard/template-list/column-template-name.html",
attrs={'th': {'data-sort': "string"}}
)
num_cores = Column(
verbose_name=_("Cores"),
attrs={'th': {'data-sort': "int"}}
)
ram_size = TemplateColumn(
"{{ record.ram_size }} MiB",
resources = TemplateColumn(
template_name="dashboard/template-list/column-template-resources.html",
verbose_name=_("Resources"),
attrs={'th': {'data-sort': "int"}},
order_by=("ram_size"),
)
lease = TemplateColumn(
"{{ record.lease.name }}",
......@@ -170,11 +169,14 @@ class TemplateListTable(Table):
verbose_name=_("Owner"),
attrs={'th': {'data-sort': "string"}}
)
created = TemplateColumn(
template_name="dashboard/template-list/column-template-created.html",
verbose_name=_("Created at"),
)
running = TemplateColumn(
template_name="dashboard/template-list/column-template-running.html",
verbose_name=_("Running"),
attrs={'th': {'data-sort': "int"}},
orderable=False,
)
actions = TemplateColumn(
verbose_name=_("Actions"),
......@@ -187,8 +189,8 @@ class TemplateListTable(Table):
model = InstanceTemplate
attrs = {'class': ('table table-bordered table-striped table-hover'
' template-list-table')}
fields = ('name', 'num_cores', 'ram_size', 'system',
'access_method', 'lease', 'owner', 'running', 'actions', )
fields = ('name', 'resources', 'system', 'access_method', 'lease',
'owner', 'created', 'running', 'actions', )
prefix = "template-"
......@@ -220,6 +222,7 @@ class LeaseListTable(Table):
fields = ('name', 'suspend_interval_seconds',
'delete_interval_seconds', )
prefix = "lease-"
empty_text = _("No available leases.")
class UserKeyListTable(Table):
......@@ -248,5 +251,41 @@ class UserKeyListTable(Table):
class Meta:
model = UserKey
attrs = {'class': ('table table-bordered table-striped table-hover')}
attrs = {'class': ('table table-bordered table-striped table-hover'),
'id': "profile-key-list-table"}
fields = ('name', 'fingerprint', 'created', 'actions')
prefix = "key-"
empty_text = _("You haven't added any public keys yet.")
class ConnectCommandListTable(Table):
name = LinkColumn(
'dashboard.views.connect-command-detail',
args=[A('pk')],
attrs={'th': {'data-sort': "string"}}
)
access_method = Column(
verbose_name=_("Access method"),
attrs={'th': {'data-sort': "string"}}
)
template = Column(
verbose_name=_("Template"),
attrs={'th': {'data-sort': "string"}}
)
actions = TemplateColumn(
verbose_name=_("Actions"),
template_name=("dashboard/connect-command-list/column-command"
"-actions.html"),
orderable=False,
)
class Meta:
model = ConnectCommand
attrs = {'class': ('table table-bordered table-striped table-hover'),
'id': "profile-command-list-table"}
fields = ('name', 'access_method', 'template', 'actions')
prefix = "cmd-"
empty_text = _(
"You don't have any custom connection commands yet. You can "
"specify commands to be displayed on VM detail pages instead of "
"the defaults.")
{% load i18n %}
<p>
{% blocktrans %}
To effortlessly connect to all kind of virtual machines you have to install the <strong>CIRCLE Client</strong>.
{% endblocktrans %}
</p>
<p class="text-info">
{% blocktrans %}
To install the <strong>CIRCLE Client</strong> click on the <strong>Download the Client</strong> button.
The button takes you to the installation detail page, where you can choose your operating system and start
the download or read more detailed information about the <strong>Client</strong>. The program can be installed on Windows XP (and above)
or Debian based Linux operating systems. To successfully install the client you have to have admin (root or elevated) rights.
After the installation complete clicking on the <strong>I have the Client installed</strong> button will launch the appropriate tool
designed for that connection with necessarily predefined configurations. This option will also save your answer and this prompt about
installation will not pop up again.
{% endblocktrans %}
</p>
<br>
<div class="pull-right">
<form method="POST" id="dashboard-client-check" action="">
{% csrf_token %}
<a class="btn btn-default" href="{% url "dashboard.views.detail" pk=instance.pk %}" data-dismiss="modal">{% trans "Cancel" %}</a>
<a class="btn btn-info" href="{{ client_download_url }}" traget="_blank">{% trans "Download the Client" %}</a>
<button data-dismiss="modal" id="client-check-button" type="submit" class="btn btn-success" title="{% trans "I downloaded and installed the client and I want to connect using it. This choice will be saved to your compuer" %}">
<i class="fa fa-external-link"></i> {% trans "I have the Client installed" %}
</button>
<input id="connect-uri" name="connect-uri" type="hidden" value="{% if instance.get_connect_uri %}{{ instance.get_connect_uri}}{% endif %}" />
<input name="vm" type="hidden" value="{% if instance.get_connect_uri %}{{ instance.pk}}{% endif %}" />
</form>
</div>
\ No newline at end of file
{% load i18n %}
{% if user and user.pk %}
{% if user.get_full_name %}
{{ user.get_full_name }}
{% else %}
{{ user.username }}
{% endif %}
{% if user.get_full_name %}{{ user.get_full_name }}{% else %}{{ user.username }}{% endif %}{% if new_line %}<br />{% endif %}
{% if show_org %}
{% if user.profile and user.profile.org_id %}
......
......@@ -2,6 +2,12 @@
<div class="modal fade" id="confirmation-modal" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
{% if box_title and ajax_title %}
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">{{ box_title }}</h4>
</div>
{% endif %}
<div class="modal-body">
{% if template %}
{% include template %}
......
......@@ -3,10 +3,11 @@
{% load sizefieldtags %}
{% include "display-form-errors.html" with form=vm_create_form %}
<form method="POST">
<form method="POST" action="{% url "dashboard.views.vm-create" %}">
{% csrf_token %}
{{ vm_create_form.template }}
{{ vm_create_form.customized }}
<div class="row">
<div class="col-sm-12">
......@@ -23,7 +24,6 @@
</div>
{% if perms.vm.set_resources %}
{{ vm_create_form.customized }}
<div class="row">
<div class="col-sm-10">
<div class="form-group">
......
......@@ -10,8 +10,9 @@
</h3>
</div>
<div class="panel-body">
{% blocktrans with owner=instance.owner fqdn=instance.primary_host %}
{{ owner }} offered to take the ownership of virtual machine {{fqdn}}.
{% blocktrans with owner=instance.owner name=instance.name id=instance.id%}
<strong>{{ owner }}</strong> offered to take the ownership of
virtual machine <strong>{{name}} ({{id}})</strong>.
Do you accept the responsility of being the host's owner?
{% endblocktrans %}
<div class="pull-right">
......
{% extends "dashboard/base.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block title-page %}{% trans "Create command template" %}{% endblock %}
{% block content %}
<div class="row">
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">
<a class="pull-right btn btn-default btn-xs" href="{% url "dashboard.views.profile-preferences" %}">{% trans "Back" %}</a>
<h3 class="no-margin"><i class="fa fa-code"></i> {% trans "Create new command template" %}</h3>
</div>
<div class="panel-body">
<form method="POST">
{% csrf_token %}
{{ form.name|as_crispy_field }}
{{ form.access_method|as_crispy_field }}
{{ form.template|as_crispy_field }}
<p class="text-muted">
{% trans "Examples" %}
</p>
<p>
<strong>SSH:</strong>
<span class="text-muted">
sshpass -p %(password)s ssh -o StrictHostKeyChecking=no cloud@%(host)s -p %(port)d
</span>
</p>
<p>
<strong>RDP:</strong>
<span class="text-muted">
rdesktop %(host)s:%(port)d -u cloud -p %(password)s
</span>
</p>
<input type="submit" class="btn btn-primary" value="{% trans "Save" %}">
</form>
</div>
</div>
</div>
</div>
{% endblock %}
{% extends "dashboard/base.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block title-page %}{% trans "Edit command template" %}{% endblock %}
{% block content %}
<div class="row">
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">
<a class="pull-right btn btn-default btn-xs" href="{% url "dashboard.views.profile-preferences" %}">{% trans "Back" %}</a>
<h3 class="no-margin"><i class="fa fa-code"></i> {% trans "Edit command template" %}</h3>
</div>
<div class="panel-body">
<form method="POST">
{% csrf_token %}
{{ form.name|as_crispy_field }}
{{ form.access_method|as_crispy_field }}
{{ form.template|as_crispy_field }}
<p class="text-muted">
{% trans "Examples" %}
</p>
<p>
<strong>SSH:</strong>
<span class="text-muted">
sshpass -p %(password)s ssh -o StrictHostKeyChecking=no cloud@%(host)s -p %(port)d
</span>
</p>
<p>
<strong>RDP:</strong>
<span class="text-muted">
rdesktop %(host)s:%(port)d -u cloud -p %(password)s
</span>
</p>
<input type="submit" class="btn btn-primary" value="{% trans "Save" %}">
</form>
</div>
</div>
</div>
</div>
{% endblock %}
{% load i18n %}
<a href="{% url "dashboard.views.connect-command-detail" pk=record.pk%}" id="template-list-edit-button" class="btn btn-default btn-xs" title="{% trans "Edit" %}">
<i class="fa fa-edit"></i>
</a>
<a data-template-pk="{{ record.pk }}" href="{% url "dashboard.views.connect-command-delete" pk=record.pk %}" class="btn btn-danger btn-xs template-delete" title="{% trans "Delete" %}">
<i class="fa fa-times"></i>
</a>
{% load crispy_forms_tags %}
{% load i18n %}
<p class="text-muted">
{% trans "User groups allow sharing templates or other resources with multiple users at once." %}
</p>
<form method="POST" action="{% url "dashboard.views.group-create" %}">
{% csrf_token %}
......
......@@ -89,13 +89,12 @@
<tr>
<td><i class="fa fa-plus"></i></td>
<td colspan="2">
<input type="text" class="form-control" name="list-new-name"
placeholder="{% trans "Name of user" %}">
{{addmemberform.new_member}}
</td>
</tr>
</tbody>
</table>
<textarea name="list-new-namelist" class="form-control"
<textarea name="new_members" class="form-control"
placeholder="{% trans "Add multiple users at once (one identifier per line)." %}"></textarea>
<div class="form-actions">
<button type="submit" class="btn btn-success">{% trans "Save" %}</button>
......
......@@ -25,7 +25,7 @@
<i class="fa {{ i.get_status_icon }}" title="{{ i.get_status_display }}"></i>
{{ i.name }}
</span>
<small class="text-muted"> {{ i.primary_host.hostname }}</small>
<small class="text-muted"> {{ i.short_hostname }}</small>
<div class="pull-right dashboard-vm-favourite" data-vm="{{ i.pk }}">
{% if i.fav %}
<i class="fa fa-star text-primary title-favourite" title="{% trans "Unfavourite" %}"></i>
......
......@@ -10,9 +10,9 @@
</h1>
</div>
<div class="row">
<div class="col-md-5" id="vm-info-pane">
<div class="big">
<span id="vm-activity-state" class="label label-{% if object.get_status_id == 'wait' %}info{% else %}{% if object.succeeded %}success{% else %}error{% endif %}{% endif %}">
<div class="col-md-6" id="vm-info-pane">
<div class="big" id="vm-activity-state">
<span class="label label-{% if object.get_status_id == 'wait' %}info{% else %}{% if object.succeeded %}success{% else %}danger{% endif %}{% endif %}">
<span>{{ object.get_status_id|upper }}</span>
</span>
</div>
......@@ -20,7 +20,7 @@
{% include "dashboard/vm-detail/_activity-timeline.html" with active=object %}
</div>
<div class="col-md-7">
<div class="col-md-6">
<div class="panel panel-default">
<!--<div class="panel-heading"><h2 class="panel-title">{% trans "Activity" %}</h2></div> -->
<div class="panel-body">
......
......@@ -11,6 +11,12 @@
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">
{% if request.user.is_superuser %}
<a href="{{ login_token }}"
class="pull-right btn btn-danger btn-xs"
title="{% trans "Log in as this user. Recommended to open in an incognito window." %}">
{% trans "Login as this user" %}</a>
{% endif %}
<a class="pull-right btn btn-default btn-xs" href="{% url "dashboard.index" %}">{% trans "Back" %}</a>
<h3 class="no-margin">
<i class="fa fa-user"></i>
......
......@@ -66,4 +66,20 @@
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">
<a href="{% url "dashboard.views.connect-command-create" %}"
class="pull-right btn btn-success btn-xs" style="margin-right: 10px;">
<i class="fa fa-plus"></i> {% trans "add command template" %}
</a>
<h3 class="no-margin"><i class="fa fa-code"></i> {% trans "Command templates" %}</h3>
</div>
<div class="panel-body">
{% render_table connectcommand_table %}
</div>
</div>
</div>
</div>
{% endblock %}
......@@ -52,6 +52,7 @@
{{ form.req_traits|as_crispy_field }}
{{ form.description|as_crispy_field }}
{{ form.system|as_crispy_field }}
{{ form.has_agent|as_crispy_field }}
</fieldset>
<fieldset>
<legend>{% trans "External resources" %}</legend>
......
......@@ -17,18 +17,37 @@
<h3 class="no-margin"><i class="fa fa-puzzle-piece"></i> {% trans "Templates" %}</h3>
</div>
<div class="panel-body">
<div class="row">
<div class="col-md-offset-8 col-md-4" id="template-list-search">
<form action="" method="GET">
<div class="input-group">
{{ search_form.s }}
<div class="input-group-btn">
{{ search_form.stype }}
<button type="submit" class="btn btn-primary input-tags">
<i class="fa fa-search"></i>
</button>
</div>
</div><!-- .input-group -->
</form>
</div><!-- .col-md-4 #template-list-search -->
</div>
</div>
<div class="panel-body">
{% render_table table %}
</div>
</div>
</div>
</div>
{% if show_lease_table %}
<div class="row">
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
{% if perms.vm.create_leases %}
<a href="{% url "dashboard.views.lease-create" %}" class="pull-right btn btn-success btn-xs" style="margin-right: 10px;">
<a href="{% url "dashboard.views.lease-create" %}"
class="pull-right btn btn-success btn-xs" style="margin-right: 10px;">
<i class="fa fa-plus"></i> {% trans "new lease" %}
</a>
{% endif %}
......@@ -55,6 +74,7 @@
</div>
{% endcomment %}
</div>
{% endif %}
{% endblock %}
{% block extra_js %}
......
{% load i18n %}
<a href="{% url "dashboard.views.vm-create" %}?template={{ record.pk }}"
class="btn btn-success btn-xs customize-vm" title="{% trans "Start" %}">
<i class="fa fa-play"></i>
</a>
<a href="{% url "dashboard.views.template-detail" pk=record.pk%}" id="template-list-edit-button" class="btn btn-default btn-xs" title="{% trans "Edit" %}">
<i class="fa fa-edit"></i>
</a>
......
{{ record.created|date }}
<br />
{{ record.created|time }}
{% include "dashboard/_display-name.html" with user=record.owner show_org=True %}
{% include "dashboard/_display-name.html" with user=record.owner show_org=True new_line=True %}
{% load i18n %}
{{ record.ram_size }}MiB RAM
<br />
{% blocktrans with num_cores=record.num_cores count count=record.num_cores %}
{{ num_cores }} CPU core
{% plural %}
{{ num_cores }} CPU cores
{% endblocktrans %}
<a href="{% url "dashboard.views.vm-list" %}?s=template:{{ record.pk }}%20status:running">
{{ record.get_running_instances.count }}
{{ record.running }}
</a>
......@@ -100,8 +100,9 @@
<div class="input-group">
<input type="text" id="vm-details-pw-input" class="form-control input-sm input-tags"
value="{{ instance.pw }}" spellcheck="false"/>
<span class="input-group-addon input-tags" id="vm-details-pw-show">
<i class="fa fa-eye" id="vm-details-pw-eye" title="Show password"></i>
<span class="input-group-addon input-tags" id="vm-details-pw-show"
title="{% trans "Show password" %}" data-container="body">
<i class="fa fa-eye" id="vm-details-pw-eye"></i>
</span>
</div>
</dd>
......@@ -113,16 +114,42 @@
</div>
</dd>
</dl>
<div class="input-group" id="dashboard-vm-details-connect-command">
{% for c in connect_commands %}
<div class="input-group dashboard-vm-details-connect-command">
<span class="input-group-addon input-tags">{% trans "Command" %}</span>
<input type="text" spellcheck="false"
value="{% if instance.get_connect_command %}{{ instance.get_connect_command }}{% else %}{% trans "Connection is not possible." %}{% endif %}"
value="{{ c }}"
id="vm-details-connection-string" class="form-control input-tags" />
<span class="input-group-addon input-tags vm-details-connection-string-copy"
title="{% trans "Select all" %}" data-container="body">
<i class="fa fa-copy"></i>
</span>
</div>
{% empty %}
<div class="input-group dashboard-vm-details-connect-command">
<span class="input-group-addon input-tags">{% trans "Command" %}</span>
<input type="text" spellcheck="false" value="{% trans "Connection is not possible." %}"
id="vm-details-connection-string" class="form-control input-tags" />
<span class="input-group-addon input-tags" id="vm-details-connection-string-copy">
<i class="fa fa-copy" title="{% trans "Select all" %}"></i>
</span>
</div>
{% endfor %}
{% if instance.get_connect_uri %}
<div id="dashboard-vm-details-connect" class="operation-wrapper">
{% if client_download %}
<a id="dashboard-vm-details-connect-button" class="btn btn-xs btn-default operation " href="{{ instance.get_connect_uri}}" title="{% trans "Connect via the CIRCLE Client" %}">
<i class="fa fa-external-link"></i> {% trans "Connect" %}
</a>
<a href="{% url "dashboard.views.client-check" %}?vm={{ instance.pk }}">{% trans "Download client" %}</a>
{% else %}
<a id="dashboard-vm-details-connect-download-button" class="btn btn-xs btn-default operation " href="{% url "dashboard.views.client-check" %}?vm={{ instance.pk }}" title="{% trans "Download the CIRCLE Client" %}">
<i class="fa fa-external-link"></i> {% trans "Connect (download client)" %}
</a>
{% endif %}
</div>
{% endif %}
</div>
<div class="col-md-8" id="vm-detail-pane">
<div class="panel panel-default" id="vm-detail-panel">
......
......@@ -9,8 +9,10 @@
{% endblocktrans %}
{% endif %}
{% if user == instance.owner or user.is_superuser %}
<span class="operation-wrapper">
<a href="{% url "dashboard.views.vm-transfer-ownership" instance.pk %}"
class="btn btn-link">{% trans "Transfer ownership..." %}</a>
class="btn btn-link operation">{% trans "Transfer ownership..." %}</a>
</span>
{% endif %}
</p>
<h3>{% trans "Permissions"|capfirst %}</h3>
......
......@@ -94,7 +94,13 @@
<dt>{% trans "Template" %}:</dt>
<dd>
{% if instance.template %}
{% if can_link_template %}
<a href="{{ instance.template.get_absolute_url }}">
{{ instance.template.name }}
</a>
{% else %}
{{ instance.template.name }}
{% endif %}
{% else %}
-
{% endif %}
......
{% extends "dashboard/base.html" %}
{% load i18n %}
{% block content %}
<div class="body-content">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="no-margin">
{% trans "Transfer ownership" %}
</h3>
</div>
<div class="panel-body">
<div class="pull-right">
<form action="" method="POST">
<div class="pull-right">
<form action="{% url "dashboard.views.vm-transfer-ownership" pk=instance.pk %}" method="POST" style="max-width: 400px;">
{% csrf_token %}
<label>
{% trans "E-mail address or identifier of user" %}:
<input name="name">
{{ form.name.label }}
</label>
<input type="submit">
</form>
<div class="input-group">
{{form.name}}
<div class="input-group-btn">
<input type="submit" value="{% trans "Save" %}" class="btn btn-primary">
</div>
</div>
</div>
{% endblock %}
</form>
</div>
......@@ -34,6 +34,12 @@
{{ search_form.s }}
<div class="input-group-btn">
{{ search_form.stype }}
</div>
<label class="input-group-addon input-tags" title="{% trans "Include deleted VMs" %}"
id="vm-list-search-checkbox-span" data-container="body">
{{ search_form.include_deleted }}
</label>
<div class="input-group-btn">
<button type="submit" class="btn btn-primary input-tags">
<i class="fa fa-search"></i>
</button>
......@@ -63,10 +69,20 @@
{% trans "Owner" as t %}
{% include "dashboard/vm-list/header-link.html" with name=t sort="owner" %}
</th>
{% if user.is_superuser %}<th data-sort="string" class="orderable sortable">
<th data-sort="string" class="orderable sortable">
{% trans "Lease" as t %}
{% include "dashboard/vm-list/header-link.html" with name=t sort="lease" %}
</th>
{% if user.is_superuser %}
<th data-sort="string" class="orderable sortable">
{% trans "IP address" as t %}
{% include "dashboard/vm-list/header-link.html" with name=t sort="ip_addr" %}
</th>
<th data-sort="string" class="orderable sortable">
{% trans "Node" as t %}
{% include "dashboard/vm-list/header-link.html" with name=t sort="node" %}
</th>{% endif %}
</th>
{% endif %}
</tr></thead><tbody>
{% for i in object_list %}
<tr class="{% cycle 'odd' 'even' %}" data-vm-pk="{{ i.pk }}">
......@@ -74,16 +90,27 @@
<td class="name"><a class="real-link" href="{% url "dashboard.views.detail" i.pk %}">{{ i.name }}</a> </td>
<td class="state">
<i class="fa fa-fw
{% if i.is_in_status_change %}
{% if show_acts_in_progress and i.is_in_status_change %}
fa-spin fa-spinner
{% else %}
{{ i.get_status_icon }}{% endif %}"></i>
<span>{{ i.get_status_display }}</span>
</td>
<td>
{% include "dashboard/_display-name.html" with user=i.owner show_org=True %}
{% if i.owner.profile %}
{{ i.owner.profile.get_display_name }}
{% else %}
{{ i.owner.username }}
{% endif %}
{# include "dashboard/_display-name.html" with user=i.owner show_org=True #}
</td>
<td class="lease "data-sort-value="{{ i.lease.name }}">
{{ i.lease.name }}
</td>
{% if user.is_superuser %}
<td class="ip_addr "data-sort-value="{{ i.ipv4 }}">
{{ i.ipv4|default:"-" }}
</td>
<td class="node "data-sort-value="{{ i.node.normalized_name }}">
{{ i.node.name|default:"-" }}
</td>
......@@ -91,7 +118,7 @@
</tr>
{% empty %}
<tr>
<td colspan="5">
<td colspan="7">
{% if request.GET.s %}
<strong>{% trans "No result." %}</strong>
{% else %}
......
{% spaceless %}
{% load django_tables2 %}
{% load i18n %}
{% if table.page %}
<div class="table-container">
{% endif %}
{% block table %}
<table{% if table.attrs %} {{ table.attrs.as_html }}{% endif %}>
{% nospaceless %}
{% block table.thead %}
<thead>
<tr>
{% for column in table.columns %}
{% if column.orderable %}
<th {{ column.attrs.th.as_html }}><a href="{% querystring table.prefixed_order_by_field=column.order_by_alias.next %}">{{ column.header }}</a></th>
{% else %}
<th {{ column.attrs.th.as_html }}>{{ column.header }}</th>
{% endif %}
{% endfor %}
</tr>
</thead>
{% endblock table.thead %}
{% block table.tbody %}
<tbody>
{% for row in table.page.object_list|default:table.rows %} {# support pagination #}
{% block table.tbody.row %}
<tr class="{{ forloop.counter|divisibleby:2|yesno:"even,odd" }}"> {# avoid cycle for Django 1.2-1.6 compatibility #}
{% for column, cell in row.items %}
<td {{ column.attrs.td.as_html }}>{% if column.localize == None %}{{ cell }}{% else %}{% if column.localize %}{{ cell|localize }}{% else %}{{ cell|unlocalize }}{% endif %}{% endif %}</td>
{% endfor %}
</tr>
{% endblock table.tbody.row %}
{% empty %}
{% if table.empty_text %}
{% block table.tbody.empty_text %}
<tr><td colspan="{{ table.columns|length }}">{{ table.empty_text }}</td></tr>
{% endblock table.tbody.empty_text %}
{% endif %}
{% endfor %}
</tbody>
{% endblock table.tbody %}
{% block table.tfoot %}
<tfoot></tfoot>
{% endblock table.tfoot %}
{% endnospaceless %}
</table>
{% endblock table %}
{% if table.page %}
</div>
{% endif %}
{% endspaceless %}
......@@ -1134,7 +1134,7 @@ class GroupDetailTest(LoginMixin, TestCase):
c = Client()
user_in_group = self.g1.user_set.count()
response = c.post('/dashboard/group/' +
str(self.g1.pk) + '/', {'list-new-name': 'user3'})
str(self.g1.pk) + '/', {'new_member': 'user3'})
self.assertEqual(user_in_group,
self.g1.user_set.count())
self.assertEqual(response.status_code, 302)
......@@ -1144,7 +1144,7 @@ class GroupDetailTest(LoginMixin, TestCase):
self.login(c, 'user3')
user_in_group = self.g1.user_set.count()
response = c.post('/dashboard/group/' +
str(self.g1.pk) + '/', {'list-new-name': 'user3'})
str(self.g1.pk) + '/', {'new_member': 'user3'})
self.assertEqual(user_in_group, self.g1.user_set.count())
self.assertEqual(response.status_code, 403)
......@@ -1153,7 +1153,7 @@ class GroupDetailTest(LoginMixin, TestCase):
self.login(c, 'superuser')
user_in_group = self.g1.user_set.count()
response = c.post('/dashboard/group/' +
str(self.g1.pk) + '/', {'list-new-name': 'user3'})
str(self.g1.pk) + '/', {'new_member': 'user3'})
self.assertEqual(user_in_group + 1, self.g1.user_set.count())
self.assertEqual(response.status_code, 302)
......@@ -1162,7 +1162,7 @@ class GroupDetailTest(LoginMixin, TestCase):
self.login(c, 'user0')
user_in_group = self.g1.user_set.count()
response = c.post('/dashboard/group/' +
str(self.g1.pk) + '/', {'list-new-name': 'user3'})
str(self.g1.pk) + '/', {'new_member': 'user3'})
self.assertEqual(user_in_group + 1, self.g1.user_set.count())
self.assertEqual(response.status_code, 302)
......@@ -1172,7 +1172,7 @@ class GroupDetailTest(LoginMixin, TestCase):
user_in_group = self.g1.user_set.count()
response = c.post('/dashboard/group/' +
str(self.g1.pk) + '/',
{'list-new-namelist': 'user1\r\nuser2'})
{'new_members': 'user1\r\nuser2'})
self.assertEqual(user_in_group + 2, self.g1.user_set.count())
self.assertEqual(response.status_code, 302)
......@@ -1182,7 +1182,7 @@ class GroupDetailTest(LoginMixin, TestCase):
user_in_group = self.g1.user_set.count()
response = c.post('/dashboard/group/' +
str(self.g1.pk) + '/',
{'list-new-namelist': 'user1\r\nnoname\r\nuser2'})
{'new_members': 'user1\r\nnoname\r\nuser2'})
self.assertEqual(user_in_group + 2, self.g1.user_set.count())
self.assertEqual(response.status_code, 302)
......@@ -1192,7 +1192,7 @@ class GroupDetailTest(LoginMixin, TestCase):
user_in_group = self.g1.user_set.count()
response = c.post('/dashboard/group/' +
str(self.g1.pk) + '/',
{'list-new-namelist': 'user1\r\nuser2'})
{'new_members': 'user1\r\nuser2'})
self.assertEqual(user_in_group, self.g1.user_set.count())
self.assertEqual(response.status_code, 403)
......@@ -1201,7 +1201,7 @@ class GroupDetailTest(LoginMixin, TestCase):
user_in_group = self.g1.user_set.count()
response = c.post('/dashboard/group/' +
str(self.g1.pk) + '/',
{'list-new-namelist': 'user1\r\nuser2'})
{'new_members': 'user1\r\nuser2'})
self.assertEqual(user_in_group, self.g1.user_set.count())
self.assertEqual(response.status_code, 302)
......@@ -1471,8 +1471,8 @@ class TransferOwnershipViewTest(LoginMixin, TestCase):
c2 = self.u2.notification_set.count()
c = Client()
self.login(c, 'user2')
response = c.post('/dashboard/vm/1/tx/')
assert response.status_code == 400
response = c.post('/dashboard/vm/1/tx/', {'name': 'userx'})
assert response.status_code == 403
self.assertEqual(self.u2.notification_set.count(), c2)
def test_owned_offer(self):
......
......@@ -39,11 +39,13 @@ from .views import (
get_vm_screenshot,
ProfileView, toggle_use_gravatar, UnsubscribeFormView,
UserKeyDelete, UserKeyDetail, UserKeyCreate,
ConnectCommandDelete, ConnectCommandDetail, ConnectCommandCreate,
StoreList, store_download, store_upload, store_get_upload_url, StoreRemove,
store_new_directory, store_refresh_toplist,
VmTraitsUpdate, VmRawDataUpdate,
GroupPermissionsView,
LeaseAclUpdateView,
ClientCheck, TokenLogin,
)
autocomplete_light.autodiscover()
......@@ -177,6 +179,16 @@ urlpatterns = patterns(
UserKeyCreate.as_view(),
name="dashboard.views.userkey-create"),
url(r'^conncmd/delete/(?P<pk>\d+)/$',
ConnectCommandDelete.as_view(),
name="dashboard.views.connect-command-delete"),
url(r'^conncmd/(?P<pk>\d+)/$',
ConnectCommandDetail.as_view(),
name="dashboard.views.connect-command-detail"),
url(r'^conncmd/create/$',
ConnectCommandCreate.as_view(),
name="dashboard.views.connect-command-create"),
url(r'^autocomplete/', include('autocomplete_light.urls')),
url(r"^store/list/$", StoreList.as_view(),
......@@ -193,4 +205,8 @@ urlpatterns = patterns(
name="dashboard.views.store-new-directory"),
url(r"^store/refresh_toplist$", store_refresh_toplist,
name="dashboard.views.store-refresh-toplist"),
url(r"^client/check$", ClientCheck.as_view(),
name="dashboard.views.client-check"),
url(r'^token-login/(?P<token>.*)/$', TokenLogin.as_view(),
name="dashboard.views.token-login"),
)
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
from lxml import etree as ET
import logging
......@@ -29,3 +31,27 @@ def domain_validator(value):
relaxng.assertValid(parsed_xml)
except Exception as e:
raise ValidationError(e.message)
def connect_command_template_validator(value):
"""Validate value as a connect command template.
>>> try: connect_command_template_validator("%(host)s")
... except ValidationError as e: print e
...
>>> connect_command_template_validator("%(host)s")
>>> try: connect_command_template_validator("%(host)s %s")
... except ValidationError as e: print e
...
[u'Invalid template string.']
"""
try:
value % {
'username': "uname",
'password': "pw",
'host': "111.111.111.111",
'port': 12345,
}
except (KeyError, TypeError, ValueError):
raise ValidationError(_("Invalid template string."))
......@@ -29,8 +29,9 @@ import requests
from django.conf import settings
from django.contrib.auth.models import User, Group
from django.contrib.auth.views import login, redirect_to_login
from django.contrib.auth.views import login as login_view, redirect_to_login
from django.contrib.auth.decorators import login_required
from django.contrib.auth import login
from django.contrib.messages.views import SuccessMessageMixin
from django.core.exceptions import (
PermissionDenied, SuspiciousOperation,
......@@ -69,13 +70,15 @@ from .forms import (
UserCreationForm, GroupProfileUpdateForm, UnsubscribeForm,
VmSaveForm, UserKeyForm, VmRenewForm, VmStateChangeForm,
CirclePasswordChangeForm, VmCreateDiskForm, VmDownloadDiskForm,
TraitsForm, RawDataForm, GroupPermissionForm, AclUserAddForm,
VmResourcesForm, VmAddInterfaceForm, VmListSearchForm
TraitsForm, RawDataForm, GroupPermissionForm, AclUserOrGroupAddForm,
VmResourcesForm, VmAddInterfaceForm, VmListSearchForm,
TemplateListSearchForm, ConnectCommandForm,
TransferOwnershipForm, AddGroupMemberForm
)
from .tables import (
NodeListTable, TemplateListTable, LeaseListTable,
GroupListTable, UserKeyListTable
GroupListTable, UserKeyListTable, ConnectCommandListTable,
)
from common.models import (
HumanReadableObject, HumanReadableException, fetch_human_exception,
......@@ -87,7 +90,8 @@ from vm.models import (
)
from storage.models import Disk
from firewall.models import Vlan, Host, Rule
from .models import Favourite, Profile, GroupProfile, FutureMember
from .models import (Favourite, Profile, GroupProfile, FutureMember,
ConnectCommand, create_profile)
from .store_api import Store, NoStoreException, NotOkException
......@@ -172,6 +176,65 @@ class FilterMixin(object):
return super(FilterMixin,
self).get_queryset().filter(**self.get_queryset_filters())
def create_fake_get(self):
self.request.GET = self._parse_get(self.request.GET)
def _parse_get(self, GET_dict):
"""
Returns a new dict from request's GET dict to filter the vm list
For example: "name:xy node:1" updates the GET dict
to resemble this URL ?name=xy&node=1
"name:xy node:1".split(":") becomes ["name", "xy node", "1"]
we pop the the first element and use it as the first dict key
then we iterate over the rest of the list and split by the last
whitespace, the first part of this list will be the previous key's
value, then last part of the list will be the next key.
The final dict looks like this: {'name': xy, 'node':1}
>>> f = FilterMixin()
>>> o = f._parse_get({'s': "hello"}).items()
>>> sorted(o) # doctest: +ELLIPSIS
[(u'name', u'hello'), (...)]
>>> o = f._parse_get({'s': "name:hello owner:test"}).items()
>>> sorted(o) # doctest: +ELLIPSIS
[(u'name', u'hello'), (u'owner', u'test'), (...)]
>>> o = f._parse_get({'s': "name:hello ws node:node 3 oh"}).items()
>>> sorted(o) # doctest: +ELLIPSIS
[(u'name', u'hello ws'), (u'node', u'node 3 oh'), (...)]
"""
s = GET_dict.get("s")
fake = GET_dict.copy()
if s:
s = s.split(":")
if len(s) < 2: # if there is no ':' in the string, filter by name
got = {'name': s[0]}
else:
latest = s.pop(0)
got = {'%s' % latest: None}
for i in s[:-1]:
new = i.rsplit(" ", 1)
got[latest] = new[0]
latest = new[1] if len(new) > 1 else None
got[latest] = s[-1]
# generate a new GET request, that is kinda fake
for k, v in got.iteritems():
fake[k] = v
return fake
def create_acl_queryset(self, model):
cleaned_data = self.search_form.cleaned_data
stype = cleaned_data.get('stype', "all")
superuser = stype == "all"
shared = stype == "shared" or stype == "all"
level = "owner" if stype == "owned" else "user"
queryset = model.get_objects_with_level(
level, self.request.user,
group_also=shared, disregard_superuser=not superuser,
)
return queryset
class IndexView(LoginRequiredMixin, TemplateView):
template_name = "dashboard/index.html"
......@@ -306,6 +369,7 @@ class VmDetailView(CheckedDetailView):
kwargs={'pk': self.object.pk}),
'ops': ops,
'op': {i.op: i for i in ops},
'connect_commands': user.profile.get_connect_commands(instance)
})
# activity data
......@@ -327,7 +391,7 @@ class VmDetailView(CheckedDetailView):
).all()
context['acl'] = AclUpdateView.get_acl_data(
instance, self.request.user, 'dashboard.views.vm-acl')
context['aclform'] = AclUserAddForm()
context['aclform'] = AclUserOrGroupAddForm()
context['os_type_icon'] = instance.os_type.replace("unknown",
"question")
# ipv6 infos
......@@ -336,7 +400,7 @@ class VmDetailView(CheckedDetailView):
# resources forms
can_edit = (
instance in Instance.get_objects_with_level("owner", user)
instance.has_level(user, "owner")
and self.request.user.has_perm("vm.change_resources"))
context['resources_form'] = VmResourcesForm(
can_edit=can_edit, instance=instance)
......@@ -349,6 +413,14 @@ class VmDetailView(CheckedDetailView):
context['can_change_resources'] = self.request.user.has_perm(
"vm.change_resources")
# client info
context['client_download'] = self.request.COOKIES.get(
'downloaded_client')
# can link template
context['can_link_template'] = (
instance.template and instance.template.has_level(user, "operator")
)
return context
def post(self, request, *args, **kwargs):
......@@ -1211,7 +1283,8 @@ class GroupDetailView(CheckedDetailView):
context['acl'] = AclUpdateView.get_acl_data(
self.object.profile, self.request.user,
'dashboard.views.group-acl')
context['aclform'] = AclUserAddForm()
context['aclform'] = AclUserOrGroupAddForm()
context['addmemberform'] = AddGroupMemberForm()
context['group_profile_form'] = GroupProfileUpdate.get_form_object(
self.request, self.object.profile)
......@@ -1228,17 +1301,15 @@ class GroupDetailView(CheckedDetailView):
if request.POST.get('new_name'):
return self.__set_name(request)
if request.POST.get('list-new-name'):
if request.POST.get('new_member'):
return self.__add_user(request)
if request.POST.get('list-new-namelist'):
if request.POST.get('new_members'):
return self.__add_list(request)
if (request.POST.get('list-new-name') is not None) and \
(request.POST.get('list-new-namelist') is not None):
return redirect(reverse_lazy("dashboard.views.group-detail",
kwargs={'pk': self.get_object().pk}))
def __add_user(self, request):
name = request.POST['list-new-name']
name = request.POST['new_member']
self.__add_username(request, name)
return redirect(reverse_lazy("dashboard.views.group-detail",
kwargs={'pk': self.object.pk}))
......@@ -1257,9 +1328,7 @@ class GroupDetailView(CheckedDetailView):
messages.warning(request, _('User "%s" not found.') % name)
def __add_list(self, request):
if not self.get_has_level()(request.user, 'operator'):
raise PermissionDenied()
userlist = request.POST.get('list-new-namelist').split('\r\n')
userlist = request.POST.get('new_members').split('\r\n')
for line in userlist:
self.__add_username(request, line)
return redirect(reverse_lazy("dashboard.views.group-detail",
......@@ -1464,6 +1533,37 @@ class GroupAclUpdateView(AclUpdateView):
return super(GroupAclUpdateView, self).get_object().profile
class ClientCheck(LoginRequiredMixin, TemplateView):
def get_template_names(self):
if self.request.is_ajax():
return ['dashboard/_modal.html']
else:
return ['dashboard/nojs-wrapper.html']
def get_context_data(self, *args, **kwargs):
context = super(ClientCheck, self).get_context_data(*args, **kwargs)
context.update({
'box_title': _('About CIRCLE Client'),
'ajax_title': False,
'client_download_url': settings.CLIENT_DOWNLOAD_URL,
'template': "dashboard/_client-check.html",
'instance': get_object_or_404(
Instance, pk=self.request.GET.get('vm')),
})
if not context['instance'].has_level(self.request.user, 'operator'):
raise PermissionDenied()
return context
def post(self, request, *args, **kwargs):
instance = get_object_or_404(Instance, pk=request.POST.get('vm'))
if not instance.has_level(request.user, 'operator'):
raise PermissionDenied()
response = HttpResponseRedirect(instance.get_absolute_url())
response.set_cookie('downloaded_client', 'True', 365 * 24 * 60 * 60)
return response
class TemplateChoose(LoginRequiredMixin, TemplateView):
def get_template_names(self):
......@@ -1478,7 +1578,7 @@ class TemplateChoose(LoginRequiredMixin, TemplateView):
self.request.user)
context.update({
'box_title': _('Choose template'),
'ajax_title': False,
'ajax_title': True,
'template': "dashboard/_template-choose.html",
'templates': templates.all(),
})
......@@ -1615,7 +1715,7 @@ class TemplateDetail(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
obj, self.request.user, 'dashboard.views.template-acl')
context['disks'] = obj.disks.all()
context['is_owner'] = obj.has_level(self.request.user, 'owner')
context['aclform'] = AclUserAddForm()
context['aclform'] = AclUserOrGroupAddForm()
return context
def get_success_url(self):
......@@ -1634,23 +1734,67 @@ class TemplateDetail(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
return kwargs
class TemplateList(LoginRequiredMixin, SingleTableView):
class TemplateList(LoginRequiredMixin, FilterMixin, SingleTableView):
template_name = "dashboard/template-list.html"
model = InstanceTemplate
table_class = TemplateListTable
table_pagination = False
allowed_filters = {
'name': "name__icontains",
'tags[]': "tags__name__in",
'tags': "tags__name__in", # for search string
'owner': "owner__username",
'ram': "ram_size",
'ram_size': "ram_size",
'cores': "num_cores",
'num_cores': "num_cores",
'access_method': "access_method__iexact",
}
def get_context_data(self, *args, **kwargs):
context = super(TemplateList, self).get_context_data(*args, **kwargs)
context['lease_table'] = LeaseListTable(Lease.objects.all(),
request=self.request)
user = self.request.user
leases_w_operator = Lease.get_objects_with_level("operator", user)
context['lease_table'] = LeaseListTable(
leases_w_operator, request=self.request,
template="django_tables2/table_no_page.html",
)
context['show_lease_table'] = (
leases_w_operator.count() > 0 or
user.has_perm("vm.create_leases")
)
context['search_form'] = self.search_form
return context
def get(self, *args, **kwargs):
self.search_form = TemplateListSearchForm(self.request.GET)
self.search_form.full_clean()
return super(TemplateList, self).get(*args, **kwargs)
def create_acl_queryset(self, model):
queryset = super(TemplateList, self).create_acl_queryset(model)
sql = ("SELECT count(*) FROM vm_instance WHERE "
"vm_instance.template_id = vm_instancetemplate.id and "
"vm_instance.destroyed_at is null and "
"vm_instance.status = 'RUNNING'")
queryset = queryset.extra(select={'running': sql})
return queryset
def get_queryset(self):
logger.debug('TemplateList.get_queryset() called. User: %s',
unicode(self.request.user))
return InstanceTemplate.get_objects_with_level(
'user', self.request.user).all()
qs = self.create_acl_queryset(InstanceTemplate)
self.create_fake_get()
try:
qs = qs.filter(**self.get_queryset_filters()).distinct()
except ValueError:
messages.error(self.request, _("Error during filtering."))
return qs.select_related("lease", "owner", "owner__profile")
class TemplateDelete(LoginRequiredMixin, DeleteView):
......@@ -1708,6 +1852,7 @@ class VmList(LoginRequiredMixin, FilterMixin, ListView):
else:
context['ops'].append(v)
context['search_form'] = self.search_form
context['show_acts_in_progress'] = self.object_list.count() < 100
return context
def get(self, *args, **kwargs):
......@@ -1743,7 +1888,7 @@ class VmList(LoginRequiredMixin, FilterMixin, ListView):
'pk': i.pk,
'name': i.name,
'icon': i.get_status_icon(),
'host': "" if not i.primary_host else i.primary_host.hostname,
'host': i.short_hostname,
'status': i.get_status_display(),
'fav': i.pk in favs,
} for i in instances]
......@@ -1752,10 +1897,16 @@ class VmList(LoginRequiredMixin, FilterMixin, ListView):
content_type="application/json",
)
def create_acl_queryset(self, model):
queryset = super(VmList, self).create_acl_queryset(model)
if not self.search_form.cleaned_data.get("include_deleted"):
queryset = queryset.filter(destroyed_at=None)
return queryset
def get_queryset(self):
logger.debug('VmList.get_queryset() called. User: %s',
unicode(self.request.user))
queryset = self.create_default_queryset()
queryset = self.create_acl_queryset(Instance)
self.create_fake_get()
sort = self.request.GET.get("sort")
......@@ -1767,54 +1918,9 @@ class VmList(LoginRequiredMixin, FilterMixin, ListView):
queryset = queryset.order_by(sort)
return queryset.filter(
**self.get_queryset_filters()).select_related('owner', 'node'
).distinct()
def create_default_queryset(self):
cleaned_data = self.search_form.cleaned_data
stype = cleaned_data.get('stype', "all")
superuser = stype == "all"
shared = stype == "shared"
level = "owner" if stype == "owned" else "user"
queryset = Instance.get_objects_with_level(
level, self.request.user,
group_also=shared, disregard_superuser=not superuser,
).filter(destroyed_at=None)
return queryset
def create_fake_get(self):
"""
Updates the request's GET dict to filter the vm list
For example: "name:xy node:1" updates the GET dict
to resemble this URL ?name=xy&node=1
"name:xy node:1".split(":") becomes ["name", "xy node", "1"]
we pop the the first element and use it as the first dict key
then we iterate over the rest of the list and split by the last
whitespace, the first part of this list will be the previous key's
value, then last part of the list will be the next key.
The final dict looks like this: {'name': xy, 'node':1}
"""
s = self.request.GET.get("s")
if s:
s = s.split(":")
if len(s) < 2: # if there is no ':' in the string, filter by name
got = {'name': s[0]}
else:
latest = s.pop(0)
got = {'%s' % latest: None}
for i in s[:-1]:
new = i.rsplit(" ", 1)
got[latest] = new[0]
latest = new[1] if len(new) > 1 else None
got[latest] = s[-1]
# generate a new GET request, that is kinda fake
fake = self.request.GET.copy()
for k, v in got.iteritems():
fake[k] = v
self.request.GET = fake
**self.get_queryset_filters()).prefetch_related(
"owner", "node", "owner__profile", "interface_set", "lease",
"interface_set__host").distinct()
class NodeList(LoginRequiredMixin, SuperuserRequiredMixin, SingleTableView):
......@@ -2020,29 +2126,35 @@ class VmCreate(LoginRequiredMixin, TemplateView):
if not request.user.has_perm('vm.create_vm'):
raise PermissionDenied()
form_error = form is not None
template = (form.template.pk if form_error
else request.GET.get("template"))
if form is None:
template_pk = request.GET.get("template")
else:
template_pk = form.template.pk
if template_pk:
template = get_object_or_404(InstanceTemplate, pk=template_pk)
if not template.has_level(request.user, 'user'):
raise PermissionDenied()
if form is None:
form = self.form_class(user=request.user, template=template)
else:
templates = InstanceTemplate.get_objects_with_level(
'user', request.user, disregard_superuser=True)
if form is None and template:
form = self.form_class(user=request.user,
template=templates.get(pk=template))
context = self.get_context_data(**kwargs)
if template:
if template_pk:
context.update({
'template': 'dashboard/_vm-create-2.html',
'box_title': _('Customize VM'),
'ajax_title': False,
'ajax_title': True,
'vm_create_form': form,
'template_o': templates.get(pk=template),
'template_o': template,
})
else:
context.update({
'template': 'dashboard/_vm-create-1.html',
'box_title': _('Create a VM'),
'ajax_title': False,
'ajax_title': True,
'templates': templates.all(),
})
return self.render_to_response(context)
......@@ -2057,52 +2169,48 @@ class VmCreate(LoginRequiredMixin, TemplateView):
raise PermissionDenied()
args = {"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)
def __create_customized(self, request, *args, **kwargs):
user = request.user
# no form yet, using POST directly:
template = get_object_or_404(InstanceTemplate,
pk=request.POST.get("template"))
form = self.form_class(
request.POST, user=request.user,
template=InstanceTemplate.objects.get(
pk=request.POST.get("template")
)
)
request.POST, user=request.user, template=template)
if not form.is_valid():
return self.get(request, form, *args, **kwargs)
post = form.cleaned_data
template = InstanceTemplate.objects.get(pk=post['template'])
# permission check
if not template.has_level(user, 'user'):
raise PermissionDenied()
if request.user.has_perm('vm.set_resources'):
ikwargs = {
'name': post['name'],
'num_cores': post['cpu_count'],
'ram_size': post['ram_size'],
'priority': post['cpu_priority'],
'max_ram_size': post['ram_size'],
'template': template,
'owner': user,
}
amount = post.get("amount", 1)
if request.user.has_perm('vm.set_resources'):
networks = [InterfaceTemplate(vlan=l, managed=l.managed)
for l in post['networks']]
ikwargs.update({
'template': template,
'owner': user,
'num_cores': post['cpu_count'],
'ram_size': post['ram_size'],
'priority': post['cpu_priority'],
'max_ram_size': post['ram_size'],
'networks': networks,
'disks': list(template.disks.all()),
})
amount = post['amount']
else:
pass
instances = Instance.mass_create_from_template(amount=amount,
**ikwargs)
return self.__deploy(request, instances)
else:
raise PermissionDenied()
def __deploy(self, request, instances, *args, **kwargs):
for i in instances:
......@@ -2232,9 +2340,9 @@ class GroupCreate(GroupCodeMixin, LoginRequiredMixin, TemplateView):
context = self.get_context_data(**kwargs)
context.update({
'template': 'dashboard/group-create.html',
'box_title': 'Create a Group',
'box_title': _('Create a Group'),
'form': form,
'ajax_title': True,
})
return self.render_to_response(context)
......@@ -2609,6 +2717,7 @@ def vm_activity(request, pk):
if not show_all:
activities = activities[:10]
response['connect_uri'] = instance.get_connect_uri()
response['human_readable_status'] = instance.get_status_display()
response['status'] = instance.status
response['icon'] = instance.get_status_icon()
......@@ -2657,11 +2766,30 @@ class FavouriteView(TemplateView):
return HttpResponse("Added.")
class TransferOwnershipView(LoginRequiredMixin, DetailView):
class TransferOwnershipView(CheckedDetailView, DetailView):
model = Instance
template_name = 'dashboard/vm-detail/tx-owner.html'
def get_template_names(self):
if self.request.is_ajax():
return ['dashboard/_modal.html']
else:
return ['dashboard/nojs-wrapper.html']
def get_context_data(self, *args, **kwargs):
context = super(TransferOwnershipView, self).get_context_data(
*args, **kwargs)
context['form'] = TransferOwnershipForm()
context.update({
'box_title': _("Transfer ownership"),
'ajax_title': True,
'template': "dashboard/vm-detail/tx-owner.html",
})
return context
def post(self, request, *args, **kwargs):
form = TransferOwnershipForm(request.POST)
if not form.is_valid():
return self.get(request)
try:
new_owner = search_user(request.POST['name'])
except User.DoesNotExist:
......@@ -2885,12 +3013,55 @@ def circle_login(request):
extra_context = {
'saml2': saml_available,
}
response = login(request, authentication_form=authentication_form,
response = login_view(request, authentication_form=authentication_form,
extra_context=extra_context)
set_language_cookie(request, response)
return response
class TokenLogin(View):
token_max_age = 120 # seconds
@classmethod
def get_salt(cls):
return unicode(cls)
@classmethod
def get_token(cls, user, sudoer):
return signing.dumps((sudoer.pk, user.pk),
salt=cls.get_salt(), compress=True)
@classmethod
def get_token_url(cls, user, sudoer):
key = cls.get_token(user, sudoer)
return reverse("dashboard.views.token-login", args=(key, ))
def get(self, request, token, *args, **kwargs):
try:
data = signing.loads(token, salt=self.get_salt(),
max_age=self.token_max_age)
logger.debug('TokenLogin token data: %s', unicode(data))
sudoer, user = data
logger.debug('Extracted TokenLogin data: sudoer: %s, user: %s',
unicode(sudoer), unicode(user))
except (signing.BadSignature, ValueError, TypeError) as e:
logger.warning('Tried invalid TokenLogin token. '
'Token: %s, user: %s. %s',
token, unicode(self.request.user), unicode(e))
raise SuspiciousOperation()
sudoer = User.objects.get(pk=sudoer)
if not sudoer.is_superuser:
raise PermissionDenied()
user = User.objects.get(pk=user)
user.backend = 'django.contrib.auth.backends.ModelBackend'
logger.warning('%s %d logged in as user %s %d',
unicode(sudoer), sudoer.pk, unicode(user), user.pk)
login(request, user)
messages.info(request, _("Logged in as user %s.") % unicode(user))
return redirect("/")
class MyPreferencesView(UpdateView):
model = Profile
......@@ -2902,11 +3073,16 @@ class MyPreferencesView(UpdateView):
user=self.request.user),
'change_language': MyProfileForm(instance=self.get_object()),
}
table = UserKeyListTable(
key_table = UserKeyListTable(
UserKey.objects.filter(user=self.request.user),
request=self.request)
table.page = None
context['userkey_table'] = table
key_table.page = None
context['userkey_table'] = key_table
cmd_table = ConnectCommandListTable(
self.request.user.command_set.all(),
request=self.request)
cmd_table.page = None
context['connectcommand_table'] = cmd_table
return context
def get_object(self, queryset=None):
......@@ -3112,6 +3288,7 @@ class UserCreationView(LoginRequiredMixin, PermissionRequiredMixin,
self.get_group(group_pk)
ret = super(UserCreationView, self).post(*args, **kwargs)
if self.object:
create_profile(self.object)
self.object.groups.add(self.group)
return redirect(
reverse('dashboard.views.group-detail', args=[group_pk]))
......@@ -3222,6 +3399,9 @@ class ProfileView(LoginRequiredMixin, DetailView):
template__in=it)
context['instances_with_access'] = context[
'instances_with_access'].filter(template__in=it)
if self.request.user.is_superuser:
context['login_token'] = TokenLogin.get_token_url(
user, self.request.user)
return context
......@@ -3311,6 +3491,82 @@ class UserKeyCreate(LoginRequiredMixin, SuccessMessageMixin, CreateView):
return kwargs
class ConnectCommandDetail(LoginRequiredMixin, SuccessMessageMixin,
UpdateView):
model = ConnectCommand
template_name = "dashboard/connect-command-edit.html"
form_class = ConnectCommandForm
success_message = _("Successfully modified command template.")
def get(self, request, *args, **kwargs):
object = self.get_object()
if object.user != request.user:
raise PermissionDenied()
return super(ConnectCommandDetail, self).get(request, *args, **kwargs)
def get_success_url(self):
return reverse_lazy("dashboard.views.connect-command-detail",
kwargs=self.kwargs)
def post(self, request, *args, **kwargs):
object = self.get_object()
if object.user != request.user:
raise PermissionDenied()
return super(ConnectCommandDetail, self).post(request, args, kwargs)
def get_form_kwargs(self):
kwargs = super(ConnectCommandDetail, self).get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
class ConnectCommandDelete(LoginRequiredMixin, DeleteView):
model = ConnectCommand
def get_success_url(self):
return reverse("dashboard.views.profile-preferences")
def get_template_names(self):
if self.request.is_ajax():
return ['dashboard/confirm/ajax-delete.html']
else:
return ['dashboard/confirm/base-delete.html']
def delete(self, request, *args, **kwargs):
object = self.get_object()
if object.user != request.user:
raise PermissionDenied()
object.delete()
success_url = self.get_success_url()
success_message = _("Command template successfully deleted.")
if request.is_ajax():
return HttpResponse(
json.dumps({'message': success_message}),
content_type="application/json",
)
else:
messages.success(request, success_message)
return HttpResponseRedirect(success_url)
class ConnectCommandCreate(LoginRequiredMixin, SuccessMessageMixin,
CreateView):
model = ConnectCommand
form_class = ConnectCommandForm
template_name = "dashboard/connect-command-create.html"
success_message = _("Successfully created a new command template.")
def get_success_url(self):
return reverse_lazy("dashboard.views.profile-preferences")
def get_form_kwargs(self):
kwargs = super(ConnectCommandCreate, self).get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
class HelpView(TemplateView):
def get_context_data(self, *args, **kwargs):
......
......@@ -215,7 +215,7 @@ class Rule(models.Model):
dst = None
if host:
ip = (host.ipv4, host.ipv6_with_prefixlen)
ip = (host.ipv4, host.ipv6_with_host_prefixlen)
if self.direction == 'in':
dst = ip
else:
......@@ -530,14 +530,30 @@ class Host(models.Model):
def incoming_rules(self):
return self.rules.filter(direction='in')
@property
def ipv6_with_prefixlen(self):
@staticmethod
def create_ipnetwork(ip, prefixlen):
try:
net = IPNetwork(self.ipv6)
net.prefixlen = self.vlan.host_ipv6_prefixlen
return net
net = IPNetwork(ip)
net.prefixlen = prefixlen
except TypeError:
return None
else:
return net
@property
def ipv4_with_vlan_prefixlen(self):
return Host.create_ipnetwork(
self.ipv4, self.vlan.network4.prefixlen)
@property
def ipv6_with_vlan_prefixlen(self):
return Host.create_ipnetwork(
self.ipv6, self.vlan.network6.prefixlen)
@property
def ipv6_with_host_prefixlen(self):
return Host.create_ipnetwork(
self.ipv6, self.vlan.host_ipv6_prefixlen)
def get_external_ipv4(self):
return self.external_ipv4 if self.external_ipv4 else self.ipv4
......@@ -600,6 +616,19 @@ class Host(models.Model):
description='created by host.save()',
type='AAAA').save()
def get_network_config(self):
interface = {'addresses': []}
if self.ipv4 and self.vlan.network4:
interface['addresses'].append(str(self.ipv4_with_vlan_prefixlen))
interface['gw4'] = str(self.vlan.network4.ip)
if self.ipv6 and self.vlan.network6:
interface['addresses'].append(str(self.ipv6_with_vlan_prefixlen))
interface['gw6'] = str(self.vlan.network6.ip)
return interface
def enable_net(self):
for i in settings.get('default_host_groups', []):
self.groups.add(Group.objects.get(name=i))
......
......@@ -6,8 +6,8 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-08-29 09:21+0200\n"
"PO-Revision-Date: 2014-08-29 09:46+0200\n"
"POT-Creation-Date: 2014-09-03 18:49+0200\n"
"PO-Revision-Date: 2014-09-03 19:00+0200\n"
"Last-Translator: Mate Ory <ory.mate@ik.bme.hu>\n"
"Language-Team: Hungarian <cloud@ik.bme.hu>\n"
"Language: hu\n"
......@@ -121,46 +121,57 @@ msgstr "Csoport vagy felhasználó neve"
msgid "group"
msgstr "csoport"
#: dashboard/forms.py:63
#: dashboard/forms.py:65
msgid "idle"
msgstr "üresjáratban"
#: dashboard/forms.py:64
#: dashboard/forms.py:66
msgid "normal"
msgstr "normál"
#: dashboard/forms.py:65
#: dashboard/forms.py:67
msgid "server"
msgstr "szerver"
#: dashboard/forms.py:66
#: dashboard/forms.py:68
msgid "realtime"
msgstr "valós idejű"
#: dashboard/forms.py:71 dashboard/forms.py:746 dashboard/forms.py:767
#: dashboard/forms.py:1034 dashboard/tables.py:229
#: dashboard/forms.py:73 dashboard/forms.py:755 dashboard/forms.py:776
#: dashboard/forms.py:1043 dashboard/tables.py:231
#: dashboard/templates/dashboard/_vm-create-2.html:19
#: dashboard/templates/dashboard/vm-list.html:54
#: dashboard/templates/dashboard/vm-list.html:60
#: dashboard/templates/dashboard/vm-detail/home.html:8 firewall/models.py:285
#: network/templates/network/index.html:22
#: network/templates/network/switch-port-edit.html:43
msgid "Name"
msgstr "Név"
#: dashboard/forms.py:72 vm/models/instance.py:141
#: dashboard/forms.py:74 vm/models/instance.py:141
msgid "Human readable name of template."
msgstr "A sablon olvasható neve."
#: dashboard/forms.py:167 dashboard/templates/dashboard/_vm-create-1.html:53
#: dashboard/forms.py:169 dashboard/templates/dashboard/_vm-create-1.html:53
#: dashboard/templates/dashboard/vm-detail/home.html:30
msgid "Description"
msgstr "Leírás"
#: dashboard/forms.py:178 dashboard/forms.py:219
#: dashboard/forms.py:180 dashboard/forms.py:228
msgid "Directory identifier"
msgstr "Címtári azonosító"
#: dashboard/forms.py:198
#: dashboard/forms.py:183
msgid ""
"If you select an item here, the members of this directory group will be "
"automatically added to the group at the time they log in. Please note that "
"other users (those with permissions like yours) may also automatically "
"become a group co-owner)."
msgstr ""
"Ha kiválaszt egy elemet, a címtári csoport tagjai automatikusan hozzáadásra "
"kerülnek, ha bejelentkeznek. Vegye figyelembe, hogy más, az önhöz hasonló "
"jogosultságú felhasználók is csoportadminisztrátorrá válhatnak."
#: dashboard/forms.py:207
#: dashboard/templates/dashboard/store/_list-box.html:57
#: network/templates/network/dashboard.html:25
#: network/templates/network/dashboard.html:41
......@@ -173,168 +184,171 @@ msgstr "Címtári azonosító"
msgid "Create"
msgstr "Létrehozás"
#: dashboard/forms.py:227 dashboard/forms.py:974 dashboard/forms.py:991
#: dashboard/forms.py:1017 dashboard/forms.py:1047 dashboard/forms.py:1072
#: dashboard/forms.py:1092 dashboard/forms.py:1121
#: dashboard/forms.py:236 dashboard/forms.py:983 dashboard/forms.py:1000
#: dashboard/forms.py:1026 dashboard/forms.py:1056 dashboard/forms.py:1097
#: dashboard/forms.py:1117 dashboard/forms.py:1146
#: dashboard/templates/dashboard/_manage_access.html:73
#: dashboard/templates/dashboard/connect-command-create.html:37
#: dashboard/templates/dashboard/connect-command-edit.html:37
#: dashboard/templates/dashboard/group-detail.html:101
#: dashboard/templates/dashboard/lease-edit.html:96
msgid "Save"
msgstr "Mentés"
#: dashboard/forms.py:259 dashboard/templates/dashboard/vm-detail.html:78
#: dashboard/forms.py:268 dashboard/templates/dashboard/vm-detail.html:78
msgid "Host"
msgstr "Gép"
#: dashboard/forms.py:329 dashboard/templates/dashboard/node-detail.html:4
#: dashboard/templates/dashboard/vm-list.html:66
#: dashboard/forms.py:338 dashboard/templates/dashboard/node-detail.html:4
#: dashboard/templates/dashboard/vm-list.html:81
msgid "Node"
msgstr "Csomópont"
#: dashboard/forms.py:408
#: dashboard/forms.py:417
msgid "Networks"
msgstr "Hálózatok"
#: dashboard/forms.py:637
#: dashboard/forms.py:646
msgid "Suspend in"
msgstr "Felfüggesztés ideje"
#: dashboard/forms.py:641 dashboard/forms.py:665
#: dashboard/forms.py:650 dashboard/forms.py:674
msgid "hours"
msgstr "óra"
#: dashboard/forms.py:646 dashboard/forms.py:670
#: dashboard/forms.py:655 dashboard/forms.py:679
msgid "days"
msgstr "nap"
#: dashboard/forms.py:651 dashboard/forms.py:675
#: dashboard/forms.py:660 dashboard/forms.py:684
msgid "weeks"
msgstr "hét"
#: dashboard/forms.py:656 dashboard/forms.py:680
#: dashboard/forms.py:665 dashboard/forms.py:689
msgid "months"
msgstr "hónap"
#: dashboard/forms.py:661
#: dashboard/forms.py:670
msgid "Delete in"
msgstr "Törlés ideje"
#: dashboard/forms.py:686 dashboard/templates/dashboard/template-edit.html:63
#: dashboard/forms.py:695 dashboard/templates/dashboard/template-edit.html:63
msgid "Save changes"
msgstr "Változások mentése"
#: dashboard/forms.py:696
#: dashboard/forms.py:705
msgid "Set expiration times even if they are shorter than the current value."
msgstr ""
"Akkor is állítsa át a lejárati időket, ha rövidebbek lesznek a jelenleginél."
#: dashboard/forms.py:699
#: dashboard/forms.py:708
msgid "Save selected lease."
msgstr "Kiválasztott bérlet mentése."
#: dashboard/forms.py:708
#: dashboard/forms.py:717
msgid "Length"
msgstr "Hossz"
#: dashboard/forms.py:723
#: dashboard/forms.py:732
msgid "Forcibly interrupt all running activities."
msgstr "Futó tevékenységek erőltetett befejezése."
#: dashboard/forms.py:724
#: dashboard/forms.py:733
msgid "Set all activities to finished state, but don't interrupt any tasks."
msgstr ""
"Minden tevékenység befejezettre állítása (a feladatok megszakítása nélkül)."
#: dashboard/forms.py:727
#: dashboard/forms.py:736
msgid "New status"
msgstr "Új állapot"
#: dashboard/forms.py:748
#: dashboard/forms.py:757
#: dashboard/templates/dashboard/store/_list-box.html:117
msgid "Size"
msgstr "Méret"
#: dashboard/forms.py:749
#: dashboard/forms.py:758
msgid "Size of disk to create in bytes or with units like MB or GB."
msgstr "Létrehozandó lemez mérete byte-okban vagy mértékegységgel (MB, GB)."
#: dashboard/forms.py:755
#: dashboard/forms.py:764
msgid "Invalid format, you can use GB or MB!"
msgstr "Érvénytelen formátum. „GB” és „MB” is használható."
#: dashboard/forms.py:768
#: dashboard/forms.py:777
msgid "URL"
msgstr "URL"
#: dashboard/forms.py:783
#: dashboard/forms.py:792
#: dashboard/templates/dashboard/node-detail/resources.html:17
msgid "Vlan"
msgstr "Vlan"
#: dashboard/forms.py:786
#: dashboard/forms.py:795
msgid "No more networks."
msgstr "Nincs több hálózat."
#: dashboard/forms.py:814 dashboard/templates/dashboard/profile.html:25
#: dashboard/forms.py:823 dashboard/templates/dashboard/profile.html:25
#: dashboard/templates/dashboard/vm-detail.html:94
msgid "Username"
msgstr "Felhasználónév"
#: dashboard/forms.py:828 dashboard/templates/dashboard/vm-detail.html:96
#: dashboard/forms.py:837 dashboard/templates/dashboard/vm-detail.html:96
msgid "Password"
msgstr "Jelszó"
#: dashboard/forms.py:833
#: dashboard/forms.py:842
msgid "Sign in"
msgstr "Bejelentkezés"
#: dashboard/forms.py:856 dashboard/templates/dashboard/profile.html:31
#: dashboard/forms.py:865 dashboard/templates/dashboard/profile.html:31
msgid "Email address"
msgstr "E-mail cím"
#: dashboard/forms.py:861
#: dashboard/forms.py:870
msgid "Reset password"
msgstr "Új jelszó"
#: dashboard/forms.py:877 dashboard/forms.py:1000
#: dashboard/forms.py:886 dashboard/forms.py:1009
msgid "Change password"
msgstr "Jelszóváltoztatás"
#: dashboard/forms.py:949
#: dashboard/forms.py:958
msgid "Add trait"
msgstr "Jellemző hozzáadása"
#: dashboard/forms.py:1036
#: dashboard/forms.py:1045
msgid "Key"
msgstr "Kulcs"
#: dashboard/forms.py:1037
#: dashboard/forms.py:1046
msgid "For example: ssh-rsa AAAAB3NzaC1yc2ED..."
msgstr "Például: ssh-rsa AAAAB3NzaC1yc2ED…"
#: dashboard/forms.py:1107
#: dashboard/forms.py:1132
msgid "permissions"
msgstr "jogosultságok"
#: dashboard/forms.py:1164
#: dashboard/forms.py:1189
msgid "owned"
msgstr "saját"
#: dashboard/forms.py:1165
#: dashboard/forms.py:1190
msgid "shared"
msgstr "osztott"
#: dashboard/forms.py:1166
#: dashboard/forms.py:1191
msgid "all"
msgstr "összes"
#: dashboard/forms.py:1173 dashboard/templates/dashboard/index-groups.html:21
#: dashboard/forms.py:1198 dashboard/forms.py:1222
#: dashboard/templates/dashboard/index-groups.html:21
#: dashboard/templates/dashboard/index-nodes.html:34
#: dashboard/templates/dashboard/index-vm.html:54
msgid "Search..."
msgstr "Keresés..."
#: dashboard/models.py:63 dashboard/templates/dashboard/index-groups.html:39
#: dashboard/models.py:65 dashboard/templates/dashboard/index-groups.html:39
#: dashboard/templates/dashboard/index-nodes.html:48
#: dashboard/templates/dashboard/index-nodes.html:73
#: dashboard/templates/dashboard/index-templates.html:38
......@@ -343,320 +357,392 @@ msgstr "Keresés..."
msgid "new"
msgstr "új"
#: dashboard/models.py:64
#: dashboard/models.py:66
msgid "delivered"
msgstr "kézbesített"
#: dashboard/models.py:65
#: dashboard/models.py:67
msgid "read"
msgstr "olvasott"
#: dashboard/models.py:105
#: dashboard/models.py:108 vm/models/instance.py:107
msgid "access method"
msgstr "elérés módja"
#: dashboard/models.py:109
msgid "Type of the remote access method."
msgstr "Távoli elérési mód típusa."
#: dashboard/models.py:110 firewall/models.py:413 firewall/models.py:440
#: firewall/models.py:828 firewall/models.py:850 firewall/models.py:871
#: storage/models.py:47 storage/models.py:86 vm/models/common.py:65
#: vm/models/common.py:89 vm/models/common.py:165 vm/models/instance.py:140
#: vm/models/instance.py:230 vm/models/node.py:65
msgid "name"
msgstr "név"
#: dashboard/models.py:111
msgid "Name of your custom command."
msgstr "Egyedi parancs neve"
#: dashboard/models.py:113
msgid "command template"
msgstr "parancssablon"
#: dashboard/models.py:114
msgid ""
"Template for connection command string. Available parameters are: username, "
"password, host, port."
msgstr ""
"Sablon a csatlakozási parancshoz. Elérhető paraméterek: username, password, "
"host, port."
#: dashboard/models.py:126
msgid "preferred language"
msgstr "választott nyelv"
#: dashboard/models.py:111 dashboard/models.py:172
#: dashboard/models.py:132 dashboard/models.py:212
msgid "Unique identifier of the person, e.g. a student number."
msgstr "A személy egyedi azonosítója, például hallgatói azonosító."
#: dashboard/models.py:114
#: dashboard/models.py:135
msgid "Use Gravatar"
msgstr "Gravatar használata"
#: dashboard/models.py:115
#: dashboard/models.py:136
msgid "Whether to use email address as Gravatar profile image"
msgstr "Használható-e az e-mail cím a Gravatar profilkép betöltésére"
#: dashboard/models.py:117
#: dashboard/models.py:138
msgid "Email notifications"
msgstr "E-mail értesítések"
#: dashboard/models.py:118
#: dashboard/models.py:139
msgid "Whether user wants to get digested email notifications."
msgstr "A felhasználó kéri-e tömbösített e-mail értesítések küldését."
#: dashboard/models.py:121
#: dashboard/models.py:142
msgid "Samba password"
msgstr "Samba jelszó"
#: dashboard/models.py:123
#: dashboard/models.py:144
msgid "Generated password for accessing store from virtual machines."
msgstr "A tárhely virtuális gépekről való eléréséhez generált jelszó."
#: dashboard/models.py:128
#: dashboard/models.py:149
msgid "disk quota"
msgstr "lemezkvóta"
#: dashboard/models.py:130
#: dashboard/models.py:151
msgid "Disk quota in mebibytes."
msgstr "Lemezkvóta mebibyte-okban."
#: dashboard/models.py:166
#: dashboard/models.py:206
msgid "Can use autocomplete."
msgstr "Használhat automatikus kiegészítést."
#: dashboard/models.py:184 firewall/models.py:274 vm/models/common.py:85
#: dashboard/models.py:224 firewall/models.py:274 vm/models/common.py:85
#: vm/models/instance.py:137 vm/models/instance.py:218
msgid "operator"
msgstr "operátor"
#: dashboard/models.py:185 firewall/models.py:100 firewall/models.py:369
#: dashboard/models.py:225 firewall/models.py:100 firewall/models.py:369
#: firewall/models.py:422 firewall/models.py:445 firewall/models.py:510
#: firewall/models.py:822 firewall/models.py:851 vm/models/common.py:86
#: firewall/models.py:851 firewall/models.py:880 vm/models/common.py:86
#: vm/models/instance.py:138 vm/models/instance.py:219
msgid "owner"
msgstr "tulajdonos"
#: dashboard/models.py:191
#: dashboard/models.py:231
msgid "Unique identifier of the group at the organization."
msgstr "A csoport egyedi szervezeti azonosítója."
#: dashboard/tables.py:38
#: dashboard/tables.py:39
msgid "Overcommit"
msgstr "Túlfoglalás"
#: dashboard/tables.py:56
#: dashboard/tables.py:57
msgid "Number of VMs"
msgstr "VM-ek száma"
#: dashboard/tables.py:62
#: dashboard/tables.py:63
msgid "Monitor"
msgstr "Állapot"
#: dashboard/tables.py:69 dashboard/tables.py:180 dashboard/tables.py:211
#: dashboard/tables.py:244
#: dashboard/tables.py:70 dashboard/tables.py:182 dashboard/tables.py:213
#: dashboard/tables.py:246 dashboard/tables.py:275
msgid "Actions"
msgstr "Műveletek"
#: dashboard/tables.py:150
msgid "Cores"
msgstr "Magok száma"
#: dashboard/tables.py:152 dashboard/templates/dashboard/_vm-create-2.html:38
#: dashboard/templates/dashboard/node-detail.html:78
#: dashboard/templates/dashboard/vm-detail.html:163
msgid "Resources"
msgstr "Erőforrások"
#: dashboard/tables.py:159 vm/models/instance.py:113
#: dashboard/tables.py:158 dashboard/templates/dashboard/vm-list.html:72
#: vm/models/instance.py:113
msgid "Lease"
msgstr "Bérlet"
#: dashboard/tables.py:170 dashboard/templates/dashboard/vm-list.html:62
#: dashboard/tables.py:169 dashboard/templates/dashboard/vm-list.html:68
#: dashboard/templates/dashboard/vm-detail/access.html:2
msgid "Owner"
msgstr "Tulajdonos"
#: dashboard/tables.py:175
#: dashboard/tables.py:174 dashboard/tables.py:241
msgid "Created at"
msgstr "Létrehozva"
#: dashboard/tables.py:178
msgid "Running"
msgstr "Fut"
#: dashboard/tables.py:234
#: dashboard/tables.py:236
msgid "Fingerprint"
msgstr "Ujjlenyomat"
#: dashboard/tables.py:239
msgid "Created at"
msgstr "Létrehozva"
#: dashboard/tables.py:257
msgid "You haven't added any public keys yet."
msgstr "Még nem adott meg publikus kulcsot."
#: dashboard/tables.py:267
msgid "Access method"
msgstr "Elérés módja"
#: dashboard/tables.py:271
#: dashboard/templates/dashboard/vm-detail/home.html:94
msgid "Template"
msgstr "Sablon"
#: dashboard/views.py:284
#: dashboard/tables.py:288
msgid ""
"You don't have any custom connection commands yet. You can specify commands "
"to be displayed on VM detail pages instead of the defaults."
msgstr ""
"Még nincs egyedi csatlakozási parancsa. Az itt megadott parancsok fognak "
"megjelenni a VM-részletező oldalon az alapértelmezettek helyett."
#: dashboard/validators.py:57
msgid "Invalid template string."
msgstr "Érvénytelen sablon."
#: dashboard/views.py:345
msgid "console access"
msgstr "konzolhozzáférés"
#: dashboard/views.py:376
#: dashboard/views.py:446
msgid "VM successfully renamed."
msgstr "A virtuális gép átnevezésre került."
#: dashboard/views.py:400
#: dashboard/views.py:470
msgid "VM description successfully updated."
msgstr "A VM leírása megváltoztatásra került."
#: dashboard/views.py:477
#: dashboard/views.py:547
msgid "There is a problem with your input."
msgstr "A megadott érték nem megfelelő."
#: dashboard/views.py:479
#: dashboard/views.py:549
msgid "Unknown error."
msgstr "Ismeretlen hiba."
#: dashboard/views.py:620
#: dashboard/views.py:690
msgid "Could not start operation."
msgstr "A művelet megkezdése meghiúsult."
#: dashboard/views.py:637
#: dashboard/views.py:707
msgid "Operation failed."
msgstr "A művelet meghiúsult."
#: dashboard/views.py:642
#: dashboard/views.py:712
msgid "Operation succeeded."
msgstr "A művelet sikeresen végrehajtásra került."
#: dashboard/views.py:644
#: dashboard/views.py:714
msgid "Operation is started."
msgstr "A művelet megkezdődött."
#: dashboard/views.py:881
#: dashboard/views.py:951
msgid "The token has expired."
msgstr "A token lejárt."
#: dashboard/views.py:1069
#: dashboard/views.py:1139
#, python-format
msgid "Failed to execute %(op)s operation on instance %(instance)s."
msgstr "%(op)s végrehajtása meghiúsult a következőn: %(instance)s."
#: dashboard/views.py:1085
#: dashboard/views.py:1155
#, python-format
msgid "You are not permitted to execute %(op)s on instance %(instance)s."
msgstr "Nem engedélyezett a(z) %(op)s végrehajtása a(z) %(instance)s gépen."
#: dashboard/views.py:1163
#: dashboard/views.py:1233
msgid "Node successfully renamed."
msgstr "A csomópont átnevezésre került."
#: dashboard/views.py:1257
#: dashboard/views.py:1327
#, python-format
msgid "User \"%s\" not found."
msgstr "Nem található „%s” felhasználó."
#: dashboard/views.py:1273
#: dashboard/views.py:1343
msgid "Group successfully renamed."
msgstr "A csoport átnevezésre került."
#: dashboard/views.py:1304
#: dashboard/views.py:1374
#, python-format
msgid "Acl user/group %(w)s successfully modified."
msgstr "A(z) %(w)s ACL felhasználó/csoport módosításra került."
#: dashboard/views.py:1306
#: dashboard/views.py:1376
#, python-format
msgid "Acl user/group %(w)s successfully added."
msgstr "A(z) %(w)s ACL felhasználó/csoport hozzáadásra került."
#: dashboard/views.py:1308
#: dashboard/views.py:1378
#, python-format
msgid "Acl user/group %(w)s successfully removed."
msgstr "A(z) %(w)s ACL felhasználó/csoport törlésre került."
#: dashboard/views.py:1392
#: dashboard/views.py:1462
msgid ""
"The original owner cannot be removed, however you can transfer ownership."
msgstr "Az eredeti tulajdonos nem törölhető, azonban a tulajdon átruházható."
#: dashboard/views.py:1428
#: dashboard/views.py:1498
#, python-format
msgid "User \"%s\" has already access to this object."
msgstr "„%s” felhasználó már hozzáfér az objektumhoz."
#: dashboard/views.py:1437
#: dashboard/views.py:1507
#, python-format
msgid "Group \"%s\" has already access to this object."
msgstr "„%s” csoport már hozzáfér az objektumhoz."
#: dashboard/views.py:1442
#: dashboard/views.py:1512
#, python-format
msgid "User or group \"%s\" not found."
msgstr "Nem található „%s” felhasználó vagy csoport."
#: dashboard/views.py:1480
#: dashboard/views.py:1548
msgid "About CIRCLE Client"
msgstr "A CIRCLE kliensről"
#: dashboard/views.py:1581
msgid "Choose template"
msgstr "Válasszon sablont"
#: dashboard/views.py:1495
#: dashboard/views.py:1596
msgid "Select an option to proceed."
msgstr "Válasszon a folytatáshoz."
#: dashboard/views.py:1526
#: dashboard/views.py:1627
msgid "Create a new base VM"
msgstr "Alap VM létrehozása"
#: dashboard/views.py:1582
#: dashboard/views.py:1683
msgid "Successfully modified template."
msgstr "A sablon módosításra került."
#: dashboard/views.py:1676
#: dashboard/views.py:1789
msgid "Error during filtering."
msgstr "A szűrés sikertelen."
#: dashboard/views.py:1814
msgid "Template successfully deleted."
msgstr "A sablon törlésre került."
#: dashboard/views.py:1919
#: dashboard/views.py:2019
msgid "Member successfully removed from group."
msgstr "A csoporttag eltávolításra került."
#: dashboard/views.py:1960
#: dashboard/views.py:2060
msgid "Future user successfully removed from group."
msgstr "A leendő csoporttag eltávolításra került."
#: dashboard/views.py:1987
#: dashboard/views.py:2087
msgid "Group successfully deleted."
msgstr "A csoport törlésre került."
#: dashboard/views.py:2036
#: dashboard/views.py:2136
msgid "Customize VM"
msgstr "VM testreszabása"
#: dashboard/views.py:2044
#: dashboard/views.py:2144
msgid "Create a VM"
msgstr "VM létrehozása"
#: dashboard/views.py:2113
#: dashboard/views.py:2213
#, python-format
msgid "Successfully created %(count)d VM."
msgid_plural "Successfully created %(count)d VMs."
msgstr[0] "%(count)d VM létrehozásra került."
msgstr[1] "%(count)d VM létrehozásra került."
#: dashboard/views.py:2118
#: dashboard/views.py:2218
msgid "VM successfully created."
msgstr "VM létrehozásra került."
#: dashboard/views.py:2147
#: dashboard/views.py:2247
#, python-format
msgid "Instance limit (%d) exceeded."
msgstr "A példányok létrehozási korlátját (%d) túllépte."
#: dashboard/views.py:2207
#: dashboard/views.py:2307
msgid "Node successfully created."
msgstr "A csomópont létrehozásra került."
#: dashboard/views.py:2251
#: dashboard/views.py:2335
msgid "Create a Group"
msgstr "Csoport létrehozása"
#: dashboard/views.py:2351
msgid "Group successfully created."
msgstr "A csoport létrehozásra került."
#: dashboard/views.py:2265
#: dashboard/views.py:2365
msgid "Group is successfully updated."
msgstr "A csoport frissítésre került."
#: dashboard/views.py:2328
#: dashboard/views.py:2428
msgid "Node successfully deleted."
msgstr "A csomópont törlésre került."
#: dashboard/views.py:2375
#: dashboard/views.py:2475
msgid "Trait successfully added to node."
msgstr "A csomópontjellemző hozzáadásra került."
#: dashboard/views.py:2420
#: dashboard/views.py:2520
msgid "Node successfully changed status."
msgstr "A csomópont állapota megváltoztatásra került."
#: dashboard/views.py:2467
#: dashboard/views.py:2567
msgid "Node successfully flushed."
msgstr "A csomópont ürítésre kerül."
#: dashboard/views.py:2486
#: dashboard/views.py:2586
msgid "Port delete confirmation"
msgstr "Porteltávolítás megerősítése"
#: dashboard/views.py:2487
#: dashboard/views.py:2587
#, python-format
msgid "Are you sure you want to close %(port)d/%(proto)s on %(vm)s?"
msgstr "Biztosan bezárja a(z) %(port)d/%(proto)s portot a következőn: %(vm)s?"
#: dashboard/views.py:2502
#: dashboard/views.py:2602
msgid "Port successfully removed."
msgstr "A port eltávolításra került."
#: dashboard/views.py:2524
#: dashboard/views.py:2624
msgid "Successfully created a new lease."
msgstr "Új bérlési mód létrehozásra került."
#: dashboard/views.py:2539
#: dashboard/views.py:2639
msgid "Successfully modified lease."
msgstr "A bérlési mód megváltoztatásra került."
#: dashboard/views.py:2569
#: dashboard/views.py:2669
msgid ""
"You can't delete this lease because some templates are still using it, "
"modify these to proceed: "
......@@ -664,19 +750,19 @@ msgstr ""
"Nem törölhető a bérleti mód, mivel az alábbi sablonok még használják. A "
"folytatáshoz módosítsa őket: "
#: dashboard/views.py:2586
#: dashboard/views.py:2686
msgid "Lease successfully deleted."
msgstr "A bérlési mód törlésre került."
#: dashboard/views.py:2668
#: dashboard/views.py:2769
msgid "Can not find specified user."
msgstr "Nem található a megadott felhasználó."
#: dashboard/views.py:2684
#: dashboard/views.py:2785
msgid "Ownership offer"
msgstr "Átruházási ajánlat"
#: dashboard/views.py:2685
#: dashboard/views.py:2786
#, python-format
msgid ""
"%(user)s offered you to take the ownership of his/her virtual machine called "
......@@ -686,49 +772,49 @@ msgstr ""
"%(user)s át kívánja ruházni %(instance)s nevű virtuális gépét Önre. <a href="
"\"%(token)s\" class=\"btn btn-success btn-small\">Elfogadás</a>"
#: dashboard/views.py:2691
#: dashboard/views.py:2792
msgid "Can not notify selected user."
msgstr "A kiválaszott felhasználó értesítése sikertelen."
#: dashboard/views.py:2694
#: dashboard/views.py:2795
#, python-format
msgid "User %s is notified about the offer."
msgstr "%s felhasználó értesítésre került az ajánlatról."
#: dashboard/views.py:2705
#: dashboard/views.py:2806
msgid "Ownership successfully transferred to you."
msgstr "A tulajdon átruházásra került."
#: dashboard/views.py:2718
#: dashboard/views.py:2819
msgid "This token is for an other user."
msgstr "A token más felhasználó nevére szól."
#: dashboard/views.py:2721
#: dashboard/views.py:2822
msgid "This token is invalid or has expired."
msgstr "A token érvénytelen vagy lejárt."
#: dashboard/views.py:2743
#: dashboard/views.py:2844
msgid "Ownership accepted"
msgstr "Átruházás elfogadva"
#: dashboard/views.py:2744
#: dashboard/views.py:2845
#, python-format
msgid "Your ownership offer of %(instance)s has been accepted by %(user)s."
msgstr "%(instance)s gépre vonatkozó átruházási ajánlatát elfogadta %(user)s."
#: dashboard/views.py:2918
#: dashboard/views.py:3024
msgid "You don't have a profile."
msgstr "Nincs profilja."
#: dashboard/views.py:2956
#: dashboard/views.py:3062
msgid "Successfully modified subscription."
msgstr "A feliratkozás módosításra került."
#: dashboard/views.py:3017
#: dashboard/views.py:3123
msgid "Disk remove confirmation"
msgstr "Lemez törlésének megerősítése"
#: dashboard/views.py:3018
#: dashboard/views.py:3124
#, python-format
msgid ""
"Are you sure you want to remove <strong>%(disk)s</strong> from <strong>"
......@@ -737,59 +823,71 @@ msgstr ""
"Biztosan eltávolítja a(z) <strong>%(disk)s</strong> lemezt a következőből: "
"%(app)s?"
#: dashboard/views.py:3037
#: dashboard/views.py:3143
msgid "Disk successfully removed."
msgstr "A lemez eltávolításra került."
#: dashboard/views.py:3134
#: dashboard/views.py:3240
#, python-format
msgid ""
"Are you sure you want to remove this interface from <strong>%(vm)s</strong>?"
msgstr ""
"Biztosan eltávolítja az interfészt a(z) <strong>%(vm)s</strong> gépből?"
#: dashboard/views.py:3148
#: dashboard/views.py:3254
msgid "Interface successfully deleted."
msgstr "Az interfész törlésre került."
#: dashboard/views.py:3249
#: dashboard/views.py:3355
msgid "Successfully modified SSH key."
msgstr "Az SSH kulcs módosításra került."
#: dashboard/views.py:3287
#: dashboard/views.py:3393
msgid "SSH key successfully deleted."
msgstr "Az SSH kulcs törlésre került."
#: dashboard/views.py:3303
#: dashboard/views.py:3409
msgid "Successfully created a new SSH key."
msgstr "Az új SSH kulcs hozzáadásra került."
#: dashboard/views.py:3352
#: dashboard/views.py:3425
msgid "Successfully modified command template."
msgstr "A parancssablon módosításra került."
#: dashboard/views.py:3468
msgid "Command template successfully deleted."
msgstr "A parancssablon törlésre került."
#: dashboard/views.py:3485
msgid "Successfully created a new command template."
msgstr "A parancssablon létrehozásra került."
#: dashboard/views.py:3534
msgid "No store."
msgstr "Nincs tárhely."
#: dashboard/views.py:3354
#: dashboard/views.py:3536
msgid "Store has some problems now. Try again later."
msgstr "A tárhely nem működik. Próbálja később."
#: dashboard/views.py:3358
#: dashboard/views.py:3540
msgid "Unknown store error."
msgstr "Ismeretlen tárhelyhiba."
#: dashboard/views.py:3375
#: dashboard/views.py:3557
msgid "Something went wrong during download."
msgstr "Hiba a letöltésben."
#: dashboard/views.py:3390 dashboard/views.py:3410
#: dashboard/views.py:3572 dashboard/views.py:3592
msgid "Unable to upload file."
msgstr "Fájl feltöltése sikertelen."
#: dashboard/views.py:3447
#: dashboard/views.py:3629
#, python-format
msgid "Unable to remove %s."
msgstr "%s törlése sikertelen."
#: dashboard/views.py:3466
#: dashboard/views.py:3648
msgid "Unable to create folder."
msgstr "Mappa létrehozása sikertelen."
......@@ -826,6 +924,76 @@ msgstr "Támogatás"
msgid "Confirmation"
msgstr "Megerősítés"
#: dashboard/templates/dashboard/_client-check.html:4
msgid ""
"\n"
" To effortlessly connect to all kind of virtual machines you have to "
"install the <strong>CIRCLE Client</strong>.\n"
" "
msgstr ""
"\n"
" A virtuális gépekhez való könnyű csatlakozáshoz telepítse a "
"<strong>CIRCLE klienst</strong>.\n"
" "
#: dashboard/templates/dashboard/_client-check.html:9
msgid ""
"\n"
" To install the <strong>CIRCLE Client</strong> click on the "
"<strong>Download the Client</strong> button. \n"
" The button takes you to the installation detail page, where you can "
"choose your operating system and start \n"
" the download or read more detailed information about the <strong>Client</"
"strong>. The program can be installed on Windows XP (and above)\n"
" or Debian based Linux operating systems. To successfully install the "
"client you have to have admin (root or elevated) rights.\n"
" After the installation complete clicking on the <strong>I have the "
"Client installed</strong> button will launch the appropriate tool\n"
" designed for that connection with necessarily predefined configurations. "
"This option will also save your answer and this prompt about\n"
" installation will not pop up again.\n"
" "
msgstr ""
"\n"
" A <strong>CIRCLE kliens</strong> letöltéséhez kattintson a "
"<strong>Kliens letöltése</strong> gombra. \n"
" A gomb a letöltőoldalra visz, ahol kiválaszthatja a megfelelő <strong>"
"kliens</strong> "
"telepítőcsomagot.\n"
" A telepítés után kattintson a <strong>Már telepítve van</strong> gombra a "
"megfelelő eszköz indításához. "
"Ezt a választást a rendszer megjegyzi.\n"
" "
#: dashboard/templates/dashboard/_client-check.html:23
#: dashboard/templates/dashboard/mass-operate.html:33
#: dashboard/templates/dashboard/operate.html:21
#: dashboard/templates/dashboard/confirm/ajax-delete.html:15
#: dashboard/templates/dashboard/confirm/ajax-node-flush.html:17
#: dashboard/templates/dashboard/confirm/ajax-node-status.html:17
#: dashboard/templates/dashboard/confirm/base-delete.html:27
#: dashboard/templates/dashboard/confirm/mass-delete.html:11
#: dashboard/templates/dashboard/confirm/node-status.html:27
#: dashboard/templates/dashboard/store/remove.html:34
msgid "Cancel"
msgstr "Mégsem"
#: dashboard/templates/dashboard/_client-check.html:24
msgid "Download the Client"
msgstr "Kliens letöltése"
#: dashboard/templates/dashboard/_client-check.html:25
msgid ""
"I downloaded and installed the client and I want to connect using it. This "
"choice will be saved to your compuer"
msgstr ""
"A kliens letöltésre és telepítésre került. Ez a beállítás "
"mentésre kerül."
#: dashboard/templates/dashboard/_client-check.html:26
msgid "I have the Client installed"
msgstr "Már telepítve van"
#: dashboard/templates/dashboard/_disk-list-element.html:10
#: dashboard/templates/dashboard/node-detail/_activity-timeline.html:28
#: dashboard/templates/dashboard/vm-detail/_activity-timeline.html:45
......@@ -847,7 +1015,7 @@ msgstr "meghiúsult"
msgid "Remove"
msgstr "Eltávolítás"
#: dashboard/templates/dashboard/_display-name.html:14
#: dashboard/templates/dashboard/_display-name.html:10
msgid "username"
msgstr "felhasználónév"
......@@ -960,7 +1128,7 @@ msgstr "Lemezek"
#: dashboard/templates/dashboard/_vm-create-1.html:40
#: dashboard/templates/dashboard/_vm-create-2.html:65
#: dashboard/templates/dashboard/base.html:46
#: dashboard/templates/dashboard/vm-detail.html:150
#: dashboard/templates/dashboard/vm-detail.html:177
msgid "Network"
msgstr "Hálózat"
......@@ -975,6 +1143,7 @@ msgstr "Testreszabás"
#: dashboard/templates/dashboard/_vm-create-1.html:68
#: dashboard/templates/dashboard/_vm-create-2.html:17
#: dashboard/templates/dashboard/template-list/column-template-actions.html:3
msgid "Start"
msgstr "Indítás"
......@@ -989,12 +1158,6 @@ msgstr ""
msgid "Amount"
msgstr "Mennyiség"
#: dashboard/templates/dashboard/_vm-create-2.html:38
#: dashboard/templates/dashboard/node-detail.html:78
#: dashboard/templates/dashboard/vm-detail.html:136
msgid "Resources"
msgstr "Erőforrások"
#: dashboard/templates/dashboard/_vm-create-2.html:56
msgid "No disks are added."
msgstr "Egy lemez sincs hozzáadva."
......@@ -1075,6 +1238,45 @@ msgstr "Adminisztráció"
msgid "Log in "
msgstr "Bejelentkezés"
#: dashboard/templates/dashboard/connect-command-create.html:5
msgid "Create command template"
msgstr "Parancssablon létrehozása"
#: dashboard/templates/dashboard/connect-command-create.html:13
#: dashboard/templates/dashboard/connect-command-edit.html:13
#: dashboard/templates/dashboard/lease-create.html:13
#: dashboard/templates/dashboard/lease-edit.html:12
#: dashboard/templates/dashboard/profile.html:13
#: dashboard/templates/dashboard/template-edit.html:14
#: dashboard/templates/dashboard/userkey-create.html:13
#: dashboard/templates/dashboard/userkey-edit.html:14
#: dashboard/templates/dashboard/confirm/base-renew.html:26
#: dashboard/templates/dashboard/confirm/node-flush.html:26
msgid "Back"
msgstr "Vissza"
#: dashboard/templates/dashboard/connect-command-create.html:14
msgid "Create new command template"
msgstr "Parancssablon létrehozása"
#: dashboard/templates/dashboard/connect-command-create.html:23
#: dashboard/templates/dashboard/connect-command-edit.html:23
msgid "Examples"
msgstr "Példák"
#: dashboard/templates/dashboard/connect-command-edit.html:5
#: dashboard/templates/dashboard/connect-command-edit.html:14
msgid "Edit command template"
msgstr "Parancssablon szerkesztése"
#: dashboard/templates/dashboard/group-create.html:5
msgid ""
"User groups allow sharing templates or other resources with multiple users "
"at once."
msgstr ""
"A felhasználói csoportok lehetővé teszik sablonok és más erőforrások "
"együttes megosztását több felhasználóval."
#: dashboard/templates/dashboard/group-detail.html:9
#: dashboard/templates/dashboard/group-detail.html:18
#: dashboard/templates/dashboard/group-detail.html:31
......@@ -1096,9 +1298,10 @@ msgstr "Átnevezés"
#: dashboard/templates/dashboard/node-detail.html:48
#: dashboard/templates/dashboard/confirm/ajax-delete.html:18
#: dashboard/templates/dashboard/confirm/mass-delete.html:12
#: dashboard/templates/dashboard/connect-command-list/column-command-actions.html:5
#: dashboard/templates/dashboard/node-list/column-actions.html:29
#: dashboard/templates/dashboard/template-list/column-lease-actions.html:5
#: dashboard/templates/dashboard/template-list/column-template-actions.html:5
#: dashboard/templates/dashboard/template-list/column-template-actions.html:9
#: dashboard/templates/dashboard/userkey-list/column-userkey-actions.html:5
msgid "Delete"
msgstr "Törlés"
......@@ -1263,7 +1466,7 @@ msgid "Mark as favorite"
msgstr "Kedvencnek jelölés"
#: dashboard/templates/dashboard/index-vm.html:40
#: dashboard/templates/dashboard/vm-list.html:97
#: dashboard/templates/dashboard/vm-list.html:124
msgid "You have no virtual machines."
msgstr "Még nincs virtuális gépe."
......@@ -1325,7 +1528,7 @@ msgstr "Nincs jogosultsága virtuális gépek indítására vagy kezelésére."
#: dashboard/templates/dashboard/instanceactivity_detail.html:25
#: dashboard/templates/dashboard/node-detail.html:91
#: dashboard/templates/dashboard/vm-detail.html:155
#: dashboard/templates/dashboard/vm-detail.html:182
#: dashboard/templates/dashboard/node-detail/activity.html:3
#: dashboard/templates/dashboard/vm-detail/activity.html:3
msgid "Activity"
......@@ -1341,7 +1544,7 @@ msgid "time"
msgstr "idő"
#: dashboard/templates/dashboard/instanceactivity_detail.html:40
#: firewall/models.py:847 firewall/models.py:973
#: firewall/models.py:876 firewall/models.py:1002
msgid "type"
msgstr "típus"
......@@ -1377,17 +1580,6 @@ msgstr "új állapot"
msgid "Create lease"
msgstr "Bérlési mód létrehozása"
#: dashboard/templates/dashboard/lease-create.html:13
#: dashboard/templates/dashboard/lease-edit.html:12
#: dashboard/templates/dashboard/profile.html:13
#: dashboard/templates/dashboard/template-edit.html:14
#: dashboard/templates/dashboard/userkey-create.html:13
#: dashboard/templates/dashboard/userkey-edit.html:14
#: dashboard/templates/dashboard/confirm/base-renew.html:26
#: dashboard/templates/dashboard/confirm/node-flush.html:26
msgid "Back"
msgstr "Vissza"
#: dashboard/templates/dashboard/lease-edit.html:5
#: dashboard/templates/dashboard/lease-edit.html:13
msgid "Edit lease"
......@@ -1415,20 +1607,8 @@ msgstr[0] ""
"példányon?\n"
msgstr[1] ""
"\n"
"Biztosan végrehajtja a(z) <strong>%(op)s</strong> műveletet a következő %"
"(count)s példányon?\n"
#: dashboard/templates/dashboard/mass-operate.html:33
#: dashboard/templates/dashboard/operate.html:21
#: dashboard/templates/dashboard/confirm/ajax-delete.html:15
#: dashboard/templates/dashboard/confirm/ajax-node-flush.html:17
#: dashboard/templates/dashboard/confirm/ajax-node-status.html:17
#: dashboard/templates/dashboard/confirm/base-delete.html:27
#: dashboard/templates/dashboard/confirm/mass-delete.html:11
#: dashboard/templates/dashboard/confirm/node-status.html:27
#: dashboard/templates/dashboard/store/remove.html:34
msgid "Cancel"
msgstr "Mégsem"
"Biztosan végrehajtja a(z) <strong>%(op)s</strong> műveletet a következő "
"%(count)s példányon?\n"
#: dashboard/templates/dashboard/node-add-trait.html:19
msgid "Add Trait"
......@@ -1473,7 +1653,7 @@ msgid "Remove node and it's host."
msgstr "Csomópont és hoszt törlése."
#: dashboard/templates/dashboard/node-detail.html:72
#: dashboard/templates/dashboard/vm-detail.html:131
#: dashboard/templates/dashboard/vm-detail.html:158
msgid "Home"
msgstr "Kezdőoldal"
......@@ -1575,6 +1755,14 @@ msgstr "SSH kulcs hozzáadása"
msgid "SSH public keys"
msgstr "SSH publikus kulcsok"
#: dashboard/templates/dashboard/profile_form.html:75
msgid "add command template"
msgstr "új parancssablon"
#: dashboard/templates/dashboard/profile_form.html:77
msgid "Command templates"
msgstr "Parancssablonok"
#: dashboard/templates/dashboard/template-edit.html:6
#: dashboard/templates/dashboard/template-edit.html:15
msgid "Edit template"
......@@ -1597,11 +1785,11 @@ msgstr "Egy lemez sincs hozzáadva!"
msgid "new template"
msgstr "új sablon"
#: dashboard/templates/dashboard/template-list.html:31
#: dashboard/templates/dashboard/template-list.html:48
msgid "new lease"
msgstr "bérlési mód létrehozása"
#: dashboard/templates/dashboard/template-list.html:34
#: dashboard/templates/dashboard/template-list.html:51
msgid "Leases"
msgstr "Bérlési módok"
......@@ -1692,32 +1880,58 @@ msgstr "A csatlakozáshoz szükséges port nincs továbbítva."
msgid "Host (IPv6)"
msgstr "Gép (IPv6)"
#: dashboard/templates/dashboard/vm-detail.html:109
#: dashboard/templates/dashboard/vm-detail.html:102
msgid "Show password"
msgstr "Jelszó megjelenítése"
#: dashboard/templates/dashboard/vm-detail.html:110
msgid "Start the VM to change the password."
msgstr "Jelszóváltoztatáshoz el kell indítani a gépet."
#: dashboard/templates/dashboard/vm-detail.html:109
#: dashboard/templates/dashboard/vm-detail.html:110
msgid "Generate new password!"
msgstr "Új jelszó generálása"
#: dashboard/templates/dashboard/vm-detail.html:116
#: dashboard/templates/dashboard/vm-detail.html:117
#: dashboard/templates/dashboard/vm-detail.html:129
msgid "Command"
msgstr "Parancs"
#: dashboard/templates/dashboard/vm-detail.html:118
msgid "Connection is not possible."
msgstr "A csatlakozás nem lehetséges."
#: dashboard/templates/dashboard/vm-detail.html:121
#: dashboard/templates/dashboard/vm-detail.html:122
#: dashboard/templates/dashboard/vm-detail.html:133
#: dashboard/templates/dashboard/vm-list.html:22
msgid "Select all"
msgstr "Összes kiválasztása"
#: dashboard/templates/dashboard/vm-detail.html:130
msgid "Connection is not possible."
msgstr "A csatlakozás nem lehetséges."
#: dashboard/templates/dashboard/vm-detail.html:140
msgid "Connect via the CIRCLE Client"
msgstr "Csatlakozás CIRCLE klienssel"
#: dashboard/templates/dashboard/vm-detail.html:141
msgid "Connect"
msgstr "Csatlakozás"
#: dashboard/templates/dashboard/vm-detail.html:143
msgid "Download client"
msgstr "Kliens letöltése"
#: dashboard/templates/dashboard/vm-detail.html:145
msgid "Download the CIRCLE Client"
msgstr "A CIRCLE kliens letöltése"
#: dashboard/templates/dashboard/vm-detail.html:146
msgid "Connect (download client)"
msgstr "Csatlakozás (kliens letöltése)"
#: dashboard/templates/dashboard/vm-detail.html:168
msgid "Console"
msgstr "Konzol"
#: dashboard/templates/dashboard/vm-detail.html:145
#: dashboard/templates/dashboard/vm-detail.html:172
msgid "Access"
msgstr "Hozzáférés"
......@@ -1729,19 +1943,27 @@ msgstr "Rendezés…"
msgid "Group actions"
msgstr "Csoportos műveletek"
#: dashboard/templates/dashboard/vm-list.html:50
#: dashboard/templates/dashboard/vm-list.html:37
msgid "Include deleted VMs"
msgstr "Törölt VM-ek megjelenítése"
#: dashboard/templates/dashboard/vm-list.html:56
msgid "ID"
msgstr "ID"
#: dashboard/templates/dashboard/vm-list.html:58
#: dashboard/templates/dashboard/vm-list.html:64
msgid "State"
msgstr "Állapot"
#: dashboard/templates/dashboard/vm-list.html:95
#: dashboard/templates/dashboard/vm-list.html:77
msgid "IP address"
msgstr "IP cím"
#: dashboard/templates/dashboard/vm-list.html:122
msgid "No result."
msgstr "Nincs eredmény."
#: dashboard/templates/dashboard/vm-list.html:114
#: dashboard/templates/dashboard/vm-list.html:141
msgid ""
"You can select multiple vm instances while holding down the <strong>CTRL</"
"strong> key."
......@@ -1749,7 +1971,7 @@ msgstr ""
"Több virtuális gépet is kiválaszthat a <strong>CTRL</strong> billentyű "
"lenyomásával."
#: dashboard/templates/dashboard/vm-list.html:115
#: dashboard/templates/dashboard/vm-list.html:142
msgid ""
"If you want to select multiple instances by one click select an instance "
"then hold down <strong>SHIFT</strong> key and select another one!"
......@@ -1892,13 +2114,14 @@ msgstr "Átruházás"
#, python-format
msgid ""
"\n"
" %(owner)s offered to take the ownership of virtual machine "
"%(fqdn)s.\n"
" <strong>%(owner)s</strong> offered to take the ownership of\n"
" virtual machine <strong>%(name)s (%(id)s)</strong>.\n"
" Do you accept the responsility of being the host's owner?\n"
" "
msgstr ""
"\n"
" %(owner)s kezdeményezte a(z) %(fqdn)s virtuális gép átruházását.\n"
" <strong>%(owner)s</strong> kezdeményezte a(z) <strong>%(name)s\n"
" (%(id)s)</strong> virtuális gép átruházását.\n"
" Elfogadja a gép birtoklásával járó felelősséget?\n"
" "
......@@ -1914,6 +2137,13 @@ msgstr "Biztosan törli a következő objektumokat?"
msgid "Status changing confirmation"
msgstr "Állapotváltozás megerősítése"
#: dashboard/templates/dashboard/connect-command-list/column-command-actions.html:2
#: dashboard/templates/dashboard/template-list/column-lease-actions.html:2
#: dashboard/templates/dashboard/template-list/column-template-actions.html:6
#: dashboard/templates/dashboard/userkey-list/column-userkey-actions.html:2
msgid "Edit"
msgstr "Szerkesztés"
#: dashboard/templates/dashboard/group-list/column-details.html:2
msgid "Members"
msgstr "Tagok"
......@@ -2095,7 +2325,7 @@ msgstr "Felsorolás"
#: dashboard/templates/dashboard/store/list.html:4
#: dashboard/templates/dashboard/store/upload.html:4
#: dashboard/templates/dashboard/vm-detail/home.html:105
#: dashboard/templates/dashboard/vm-detail/home.html:111
msgid "Store"
msgstr "Tárhely"
......@@ -2167,11 +2397,20 @@ msgstr "Fájlfeltöltés"
msgid "Currently uploading to"
msgstr "Feltöltés helye:"
#: dashboard/templates/dashboard/template-list/column-lease-actions.html:2
#: dashboard/templates/dashboard/template-list/column-template-actions.html:2
#: dashboard/templates/dashboard/userkey-list/column-userkey-actions.html:2
msgid "Edit"
msgstr "Szerkesztés"
#: dashboard/templates/dashboard/template-list/column-template-resources.html:5
#, python-format
msgid ""
"\n"
" %(num_cores)s CPU core\n"
msgid_plural ""
"\n"
" %(num_cores)s CPU cores\n"
msgstr[0] ""
"\n"
" %(num_cores)s CPU mag\n"
msgstr[1] ""
"\n"
" %(num_cores)s CPU mag\n"
#: dashboard/templates/dashboard/vm-detail/_activity-timeline.html:29
msgid "Abort"
......@@ -2261,10 +2500,6 @@ msgstr "Nincs címke."
msgid "Add tag"
msgstr "Címke hozzáadása"
#: dashboard/templates/dashboard/vm-detail/home.html:94
msgid "Template"
msgstr "Sablon"
#: dashboard/templates/dashboard/vm-detail/network.html:8 vm/operations.py:121
msgid "add interface"
msgstr "új interfész"
......@@ -2416,8 +2651,8 @@ msgid "If the rule matches egress or ingress packets."
msgstr "A szabály kimenő vagy bejövő csomagokra illeszkedik."
#: firewall/models.py:68 firewall/models.py:334 firewall/models.py:419
#: firewall/models.py:442 firewall/models.py:499 firewall/models.py:828
#: firewall/models.py:852 firewall/models.py:922 vm/models/instance.py:142
#: firewall/models.py:442 firewall/models.py:499 firewall/models.py:857
#: firewall/models.py:881 firewall/models.py:951 vm/models/instance.py:142
#: vm/models/instance.py:232
msgid "description"
msgstr "leírás"
......@@ -2532,7 +2767,7 @@ msgstr "vlan-csoport"
msgid "Group of vlans the rule applies to (if type is vlan)."
msgstr "Erre a vlan-csoportra vonatkozik a szabály (ha a típus vlan)."
#: firewall/models.py:133 firewall/models.py:845 firewall/models.py:965
#: firewall/models.py:133 firewall/models.py:874 firewall/models.py:994
#: vm/models/network.py:67 vm/models/node.py:70
msgid "host"
msgstr "gép"
......@@ -2715,14 +2950,6 @@ msgstr ""
msgid "All IP addresses are already in use."
msgstr "Minden IP cím használatban van."
#: firewall/models.py:413 firewall/models.py:440 firewall/models.py:799
#: firewall/models.py:821 firewall/models.py:842 storage/models.py:47
#: storage/models.py:86 vm/models/common.py:65 vm/models/common.py:89
#: vm/models/common.py:165 vm/models/instance.py:140 vm/models/instance.py:230
#: vm/models/node.py:65
msgid "name"
msgstr "név"
#: firewall/models.py:414 firewall/models.py:441
msgid "The name of the group."
msgstr "A csoport neve."
......@@ -2826,72 +3053,72 @@ msgstr "csoportok"
msgid "Host groups the machine is part of."
msgstr "Gépcsoportok, amelyeknek tagja a gép."
#: firewall/models.py:553
#: firewall/models.py:569
msgid "If shared_ip has been checked, external_ipv4 has to be unique."
msgstr ""
"Amennyiben az osztott IP mező igaz, a külső IPv4 cím mező egyedi kell legyen."
#: firewall/models.py:556
#: firewall/models.py:572
msgid "You can't use another host's NAT'd address as your own IPv4."
msgstr "Nem használható másik gép NAT-olt címe saját IPv4 címként."
#: firewall/models.py:649
#: firewall/models.py:678
#, python-format
msgid "All %s ports are already in use."
msgstr "Minden %s port használatban van."
#: firewall/models.py:667
#: firewall/models.py:696
#, python-format
msgid "Port %(proto)s %(public)s is already in use."
msgstr "A(z) %(public)s %(proto)s port használatban van."
#: firewall/models.py:685
#: firewall/models.py:714
msgid "Only ports above 1024 can be used."
msgstr "Csak az 1024 feletti portok használhatóak."
#: firewall/models.py:824 firewall/models.py:854 firewall/models.py:924
#: firewall/models.py:952 firewall/models.py:976
#: firewall/models.py:853 firewall/models.py:883 firewall/models.py:953
#: firewall/models.py:981 firewall/models.py:1005
msgid "created_at"
msgstr "létrehozva"
#: firewall/models.py:826 firewall/models.py:856 firewall/models.py:926
#: firewall/models.py:954 firewall/models.py:978
#: firewall/models.py:855 firewall/models.py:885 firewall/models.py:955
#: firewall/models.py:983 firewall/models.py:1007
msgid "modified_at"
msgstr "módosítva"
#: firewall/models.py:827 firewall/models.py:850
#: firewall/models.py:856 firewall/models.py:879
msgid "ttl"
msgstr "ttl"
#: firewall/models.py:843
#: firewall/models.py:872
msgid "domain"
msgstr "tartomány"
#: firewall/models.py:849
#: firewall/models.py:878
msgid "address"
msgstr "cím"
#: firewall/models.py:871
#: firewall/models.py:900
msgid "Address must be specified!"
msgstr "A cím megadása kötelező."
#: firewall/models.py:884
#: firewall/models.py:913
msgid "Unknown record type."
msgstr "Ismeretlen rekordtípus."
#: firewall/models.py:918
#: firewall/models.py:947
msgid "untagged vlan"
msgstr "untagged vlan"
#: firewall/models.py:921
#: firewall/models.py:950
msgid "tagged vlans"
msgstr "tagged vlanok"
#: firewall/models.py:944
#: firewall/models.py:973
msgid "interface"
msgstr "interfész"
#: firewall/models.py:945
#: firewall/models.py:974
msgid ""
"The name of network interface the gateway should serve this network on. For "
"example eth2."
......@@ -2899,23 +3126,23 @@ msgstr ""
"Azon hálózati interfész nevve, amelyen az útválasztó ezt a hálózatot "
"kiszolgálja. Például eth2."
#: firewall/models.py:950
#: firewall/models.py:979
msgid "switch port"
msgstr "switch port"
#: firewall/models.py:966
#: firewall/models.py:995
msgid "reason"
msgstr "indok"
#: firewall/models.py:968
#: firewall/models.py:997
msgid "short message"
msgstr "rövid üzenet"
#: firewall/models.py:988
#: firewall/models.py:1017
msgid "blacklist item"
msgstr "tiltólista eleme"
#: firewall/models.py:989
#: firewall/models.py:1018
msgid "blacklist"
msgstr "tiltólista"
......@@ -3487,7 +3714,7 @@ msgstr ""
"lemezen, mivel az alapja, „%(b_name)s” (%(b_pk)s) [%(b_filename)s] nem "
"volt még csatolva."
#: storage/models.py:413 storage/models.py:488 vm/models/instance.py:895
#: storage/models.py:413 storage/models.py:488 vm/models/instance.py:897
msgid "Operation aborted by user."
msgstr "A műveletet a felhasználó megszakította."
......@@ -4152,37 +4379,37 @@ msgstr "Használói jogosultság szükséges a(z) %(vlan)s vlan-hoz."
msgid "attach network"
msgstr "hálózat csatolása"
#: vm/operations.py:158
#: vm/operations.py:159
#, python-format
msgid "add %(vlan)s interface"
msgstr "új %(vlan)s interfész"
#: vm/operations.py:169
#: vm/operations.py:170
msgid "create disk"
msgstr "lemez létrehozása"
#: vm/operations.py:170
#: vm/operations.py:171
msgid "Create and attach empty disk to the virtual machine."
msgstr "Üres lemez létehozása és virtuális géphez csatolása."
#: vm/operations.py:191
#: vm/operations.py:192
msgid "deploying disk"
msgstr "lemez létrehozása"
#: vm/operations.py:196 vm/operations.py:241
#: vm/operations.py:197 vm/operations.py:243
msgid "attach disk"
msgstr "lemez csatolása"
#: vm/operations.py:202
#: vm/operations.py:203
#, python-format
msgid "create disk %(name)s (%(size)s)"
msgstr "%(name)s lemez létrehozása (%(size)s)"
#: vm/operations.py:212
#: vm/operations.py:213
msgid "download disk"
msgstr "lemez letöltése"
#: vm/operations.py:213
#: vm/operations.py:214
msgid ""
"Download and attach disk image (ISO file) for the virtual machine. Most "
"operating systems do not detect a new optical drive, so you may have to "
......@@ -4192,16 +4419,16 @@ msgstr ""
"operációs rendszer nem érzékeli az új optikai meghajtót, így valószínűleg "
"újra kell indítania a virtuális gépet."
#: vm/operations.py:235
#: vm/operations.py:237
#, python-format
msgid "download %(name)s"
msgstr "%(name)s letöltése"
#: vm/operations.py:251
#: vm/operations.py:253
msgid "deploy"
msgstr "indítás"
#: vm/operations.py:252
#: vm/operations.py:254
msgid ""
"Deploy and start the virtual machine (including storage and network "
"configuration)."
......@@ -4209,58 +4436,58 @@ msgstr ""
"Virtuális gép elhelyezése és indítása (valamint a lemezek és a hálózat "
"beállítása)."
#: vm/operations.py:269
#: vm/operations.py:271
#, python-format
msgid "virtual machine successfully deployed to node: %(node)s"
msgstr "a virtuális gép sikeresen elindítva a következő csomóponton: %(node)s"
#: vm/operations.py:281
#: vm/operations.py:283
msgid "deploy disks"
msgstr "lemez létrehozása"
#: vm/operations.py:286
#: vm/operations.py:288
msgid "deploy virtual machine"
msgstr "virtuális gép létrehozása"
#: vm/operations.py:287
#: vm/operations.py:289
#, python-format
msgid "deploy vm to %(node)s"
msgstr "vm létrehozása: %(node)s"
#: vm/operations.py:296 vm/operations.py:408 vm/operations.py:731
#: vm/operations.py:298 vm/operations.py:411 vm/operations.py:736
msgid "deploy network"
msgstr "hálózati kapcsolat létrehozása"
#: vm/operations.py:302
#: vm/operations.py:304
msgid "boot virtual machine"
msgstr "virtuális gép indítása"
#: vm/operations.py:317
#: vm/operations.py:319
msgid "destroy"
msgstr "megsemmisítés"
#: vm/operations.py:318
#: vm/operations.py:320
msgid "Permanently destroy virtual machine, its network settings and disks."
msgstr ""
"Virtuális gép és lemezeinek, hálózati beállításainak végleges eltávolítása."
#: vm/operations.py:327
#: vm/operations.py:329
msgid "destroy network"
msgstr "hálózat megsemmisítése"
#: vm/operations.py:336
#: vm/operations.py:338
msgid "destroy virtual machine"
msgstr "virtuális gép megsemmisítése"
#: vm/operations.py:342
#: vm/operations.py:344
msgid "destroy disks"
msgstr "lemez megsemmisítése"
#: vm/operations.py:365
#: vm/operations.py:367
msgid "migrate"
msgstr "migrálás"
#: vm/operations.py:366
#: vm/operations.py:368
msgid ""
"Move virtual machine to an other worker node with a few seconds of "
"interruption (live migration)."
......@@ -4268,38 +4495,38 @@ msgstr ""
"A virtuális gép áthelyezése egy másik számítási csomópontra néhány másodperc "
"kimaradással (live migration)."
#: vm/operations.py:375
#: vm/operations.py:378
msgid "redeploy network (rollback)"
msgstr "hálózati kapcsolat újraépítése (visszagörgetés)"
#: vm/operations.py:382
#: vm/operations.py:385
msgid "schedule"
msgstr "ütemezés"
#: vm/operations.py:389
#: vm/operations.py:392
#, python-format
msgid "migrate to %(node)s"
msgstr "migrálás %(node)s csomópontra"
#: vm/operations.py:399 vm/operations.py:684
#: vm/operations.py:402 vm/operations.py:689
msgid "shutdown network"
msgstr "hálózati kapcsolat leállítása"
#: vm/operations.py:418
#: vm/operations.py:421
msgid "reboot"
msgstr "újraindítás"
#: vm/operations.py:419
#: vm/operations.py:422
msgid ""
"Warm reboot virtual machine by sending Ctrl+Alt+Del signal to its console."
msgstr ""
"Virtuális gép újraindítása a konzoljára a Ctrl+Alt+Del kombináció küldésével."
#: vm/operations.py:434
#: vm/operations.py:437
msgid "remove interface"
msgstr "interfész törlése"
#: vm/operations.py:435
#: vm/operations.py:438
msgid ""
"Remove the specified network interface and erase IP address allocations, "
"related firewall rules and hostnames."
......@@ -4307,50 +4534,50 @@ msgstr ""
"A kiválasztott hálózati interfész eltávolítása, a foglalt IP címek, "
"tűzfalszabályok és gépnevek törlése."
#: vm/operations.py:445
#: vm/operations.py:448
msgid "detach network"
msgstr "hálózat lecsatolása"
#: vm/operations.py:454
#: vm/operations.py:457
#, python-format
msgid "remove %(vlan)s interface"
msgstr "%(vlan)s interfész törlése"
#: vm/operations.py:464
#: vm/operations.py:467
msgid "remove disk"
msgstr "lemez eltávolítása"
#: vm/operations.py:465
#: vm/operations.py:468
msgid ""
"Remove the specified disk from the virtual machine, and destroy the data."
msgstr "A megadott lemez eltávolítása a virtuális gépből és az adat törlése."
#: vm/operations.py:474
#: vm/operations.py:477
msgid "detach disk"
msgstr "lemez leválasztása"
#: vm/operations.py:479
#: vm/operations.py:482
msgid "destroy disk"
msgstr "lemez megsemmisítése"
#: vm/operations.py:484
#: vm/operations.py:487
#, python-format
msgid "remove disk %(name)s"
msgstr "%(name)s lemez eltávolítása"
#: vm/operations.py:493
#: vm/operations.py:496
msgid "reset"
msgstr "reset"
#: vm/operations.py:494
#: vm/operations.py:497
msgid "Cold reboot virtual machine (power cycle)."
msgstr "Virtuális gép hideg újraindítása (hálózati tápellátás megszakítása)."
#: vm/operations.py:507
#: vm/operations.py:510
msgid "save as template"
msgstr "mentés sablonként"
#: vm/operations.py:508
#: vm/operations.py:511
msgid ""
"Save virtual machine as a template so they can be shared with users and "
"groups. Anyone who has access to a template (and to the networks it uses) "
......@@ -4360,16 +4587,16 @@ msgstr ""
"felhasználókkal és csoportokkal. Mindenki, aki hozzáférést kap egy sablonhoz "
"(és az általa használt hálózatokhoz), képes lesz egy példányát elindítani."
#: vm/operations.py:577
#: vm/operations.py:581
#, python-format
msgid "saving disk %(name)s"
msgstr "%(name)s lemez mentése"
#: vm/operations.py:604
#: vm/operations.py:608
msgid "shutdown"
msgstr "leállítás"
#: vm/operations.py:605
#: vm/operations.py:609
msgid ""
"Try to halt virtual machine by a standard ACPI signal, allowing the "
"operating system to keep a consistent state. The operation will fail if the "
......@@ -4379,11 +4606,11 @@ msgstr ""
"operációs rendszer számár a szabályos leállást. A művelet meghiúsul, ha a "
"gép nem áll le."
#: vm/operations.py:626
#: vm/operations.py:630
msgid "shut off"
msgstr "kikapcsolás"
#: vm/operations.py:627
#: vm/operations.py:631
msgid ""
"Forcibly halt a virtual machine without notifying the operating system. This "
"operation will even work in cases when shutdown does not, but the operating "
......@@ -4396,11 +4623,11 @@ msgstr ""
"rendszer és a fájlrendszer sérülhet, adatvesztés történhet. A művelet hatása "
"hasonló, mint egy fizikai gép tápellátásának megszüntetése."
#: vm/operations.py:658
#: vm/operations.py:662
msgid "sleep"
msgstr "altatás"
#: vm/operations.py:659
#: vm/operations.py:663
msgid ""
"Suspend virtual machine. This means the machine is stopped and its memory is "
"saved to disk, so if the machine is waked up, all the applications will keep "
......@@ -4416,15 +4643,15 @@ msgstr ""
"megállhatnak visszaállítás után. A felfüggesztés ideje alatt a virtuális gép "
"csak tárterületet és hálózati erőforrásokat foglal."
#: vm/operations.py:690
#: vm/operations.py:695
msgid "suspend virtual machine"
msgstr "virtuális gép felfüggesztése"
#: vm/operations.py:703
#: vm/operations.py:708
msgid "wake up"
msgstr "virtuális gép ébresztése"
#: vm/operations.py:704
#: vm/operations.py:709
msgid ""
"Wake up sleeping (suspended) virtual machine. This will load the saved "
"memory of the system and start the virtual machine from this state."
......@@ -4432,15 +4659,15 @@ msgstr ""
"Alvó (felfüggesztett) gép ébresztése: az elmentett memóriatartalom "
"visszatöltése és a virtuális gép indítása ebből a mentett állapotból."
#: vm/operations.py:725
#: vm/operations.py:730
msgid "resume virtual machine"
msgstr "virtuális gép ébresztése"
#: vm/operations.py:746
#: vm/operations.py:751
msgid "renew"
msgstr "megújítás"
#: vm/operations.py:747
#: vm/operations.py:752
msgid ""
"Virtual machines are suspended and destroyed after they expire. This "
"operation renews expiration times according to the lease type. If the "
......@@ -4450,7 +4677,7 @@ msgstr ""
"a művelet megújítja a bérletet a kiválasztott típusnak megfelelően. Ha egy "
"gép közeledik a lejárathoz, a tulajdonost értesítjük."
#: vm/operations.py:760
#: vm/operations.py:765
msgid ""
"Renewing the machine with the selected lease would result in its suspension "
"time get earlier than before."
......@@ -4458,7 +4685,7 @@ msgstr ""
"A gép megújítása a kiválasztott bérleti mód mellett a felfüggesztési időt "
"korábbra állította volna, mint a jelenlegi érték."
#: vm/operations.py:765
#: vm/operations.py:770
msgid ""
"Renewing the machine with the selected lease would result in its delete time "
"get earlier than before."
......@@ -4466,17 +4693,17 @@ msgstr ""
"A gép megújítása a kiválasztott bérleti mód mellett a törlési időt korábbra "
"állította volna, mint a jelenlegi érték."
#: vm/operations.py:773
#: vm/operations.py:778
#, python-format
msgid "Renewed to suspend at %(suspend)s and destroy at %(delete)s."
msgstr ""
"Megújítás után felfüggesztés ideje: %(suspend)s, a törlésé: %(delete)s."
#: vm/operations.py:783
#: vm/operations.py:788
msgid "emergency state change"
msgstr "vész-állapotváltás"
#: vm/operations.py:784
#: vm/operations.py:789
msgid ""
"Change the virtual machine state to NOSTATE. This should only be used if "
"manual intervention was needed in the virtualization layer, and the machine "
......@@ -4487,28 +4714,28 @@ msgstr ""
"rétegben, és úgy szeretné a gépet újból elindítani, hogy ne vesszenek el "
"lemezei vagy hálózati erőforrásai."
#: vm/operations.py:796
#: vm/operations.py:801
msgid "Activity is forcibly interrupted."
msgstr "A tevékenység erőszakos megszakításra került."
#: vm/operations.py:838
#: vm/operations.py:843
msgid "flush"
msgstr "ürítés"
#: vm/operations.py:839
#: vm/operations.py:844
msgid "Disable node and move all instances to other ones."
msgstr "A csomópont tiltása és az összes példány másikakra mozgatása."
#: vm/operations.py:854
#: vm/operations.py:860
#, python-format
msgid "migrate %(instance)s (%(pk)s)"
msgstr "%(instance)s (%(pk)s) migrálása"
#: vm/operations.py:866
#: vm/operations.py:872
msgid "screenshot"
msgstr "képernyőkép"
#: vm/operations.py:867
#: vm/operations.py:873
msgid ""
"Get a screenshot about the virtual machine's console. A key will be pressed "
"on the keyboard to stop screensaver."
......@@ -4516,11 +4743,11 @@ msgstr ""
"Képernyőkép készítése a virtuális gép konzoljáról. Egy billentyűnyomást "
"követően készül a kép a képernyővédő miatt."
#: vm/operations.py:884
#: vm/operations.py:890
msgid "recover"
msgstr "visszaállítás"
#: vm/operations.py:885
#: vm/operations.py:891
msgid ""
"Try to recover virtual machine disks from destroyed state. Network resources "
"(allocations) are already lost, so you will have to manually add interfaces "
......@@ -4530,15 +4757,15 @@ msgstr ""
"hálózati erőforrások foglalásai már végleg elvesztek, így az interfészeket "
"kézzel kell a visszaállítás után pótolni."
#: vm/operations.py:914
#: vm/operations.py:920
msgid "resources change"
msgstr "erőforrások módosítása"
#: vm/operations.py:915
#: vm/operations.py:921
msgid "Change resources of a stopped virtual machine."
msgstr "Leállított virtuális gép erőforrásainak változtatása."
#: vm/operations.py:932
#: vm/operations.py:938
#, python-format
msgid ""
"Priority: %(priority)s, Num cores: %(num_cores)s, Ram size: %(ram_size)s"
......@@ -4546,11 +4773,11 @@ msgstr ""
"Prioritás: %(priority)s, magok száma: %(num_cores)s, memória mérete: "
"%(ram_size)s"
#: vm/operations.py:963
#: vm/operations.py:969
msgid "password reset"
msgstr "jelszó visszaállítása"
#: vm/operations.py:964
#: vm/operations.py:970
msgid ""
"Generate and set a new login password on the virtual machine. This operation "
"requires the agent running. Resetting the password is not warranted to allow "
......@@ -4560,11 +4787,11 @@ msgstr ""
"művelet megköveteli az ügynök futását. A jelszó átállítása nem garantálja a "
"sikeres belépést, mivel más beállítások is megakadályozhatják ezt."
#: vm/operations.py:986
#: vm/operations.py:992
msgid "mount store"
msgstr "tárhely csatolása"
#: vm/operations.py:988
#: vm/operations.py:994
msgid ""
"This operation attaches your personal file store. Other users who have "
"access to this machine can see these files as well."
......@@ -4664,10 +4891,6 @@ msgstr "soha"
msgid "%(name)s (suspend: %(s)s, remove: %(r)s)"
msgstr "%(name)s (felfüggesztés: %(s)s, törlés: %(r)s)"
#: vm/models/instance.py:107
msgid "access method"
msgstr "elérés módja"
#: vm/models/instance.py:108
msgid "Primary remote access method."
msgstr "Elsődleges távoli elérési mód."
......@@ -4901,7 +5124,7 @@ msgstr "példány létrehozása"
msgid "vm state changed to %(state)s"
msgstr "VM állapota erre változott: %(state)s"
#: vm/models/instance.py:659
#: vm/models/instance.py:661
#, python-format
msgid ""
"Your instance <a href=\"%(url)s\">%(instance)s</a> is going to expire. It "
......@@ -4913,7 +5136,7 @@ msgstr ""
"kerül. Kérjük, <a href=\"%(token)s\">újítsa meg</a> vagy <a href=\"%(url)s"
"\">törölje</a> most."
#: vm/models/instance.py:671
#: vm/models/instance.py:673
#, python-format
msgid ""
"%(failed)s notifications failed and %(success) succeeded. Failed ones are: "
......@@ -4922,7 +5145,7 @@ msgstr ""
"%(failed)s értesítés sikertelen és %(success) sikeres. A sikertelenek: "
"%(faileds)s."
#: vm/models/instance.py:673
#: vm/models/instance.py:675
#, python-format
msgid ""
"%(failed)s notifications failed and %(success) succeeded. Failed ones are: "
......@@ -4931,16 +5154,16 @@ msgstr ""
"%(failed)s értesítés sikertelen és %(success) sikeres. A sikertelenek: "
"%(faileds_ex)s."
#: vm/models/instance.py:681
#: vm/models/instance.py:683
#, python-format
msgid "%(success)s notifications succeeded."
msgstr "%(success)s sikeres értesítés."
#: vm/models/instance.py:686
#: vm/models/instance.py:688
msgid "notify owner about expiration"
msgstr "tulaj értesítése a lejáratról"
#: vm/models/instance.py:694
#: vm/models/instance.py:696
#, python-format
msgid "%(instance)s expiring soon"
msgstr "%(instance)s hamarosan lejár"
......@@ -5038,14 +5261,10 @@ msgstr "elérhető"
msgid "disable node"
msgstr "csomópont tiltása"
#: vm/tasks/local_agent_tasks.py:36
#: vm/tasks/local_agent_tasks.py:39
msgid "cleanup"
msgstr "takarítás"
#: vm/tasks/local_agent_tasks.py:39
msgid "restart networking"
msgstr "hálózat újratöltése"
#: vm/tasks/local_agent_tasks.py:42
msgid "change password"
msgstr "jelszóváltoztatás"
......@@ -5058,28 +5277,36 @@ msgstr "óra beállítása"
msgid "set hostname"
msgstr "gépnév beállítása"
#: vm/tasks/local_agent_tasks.py:81
#: vm/tasks/local_agent_tasks.py:55
msgid "change ip"
msgstr "IP cím beállítása"
#: vm/tasks/local_agent_tasks.py:59
msgid "restart networking"
msgstr "hálózat újratöltése"
#: vm/tasks/local_agent_tasks.py:92
msgid "agent"
msgstr "ügynök"
#: vm/tasks/local_agent_tasks.py:84
#: vm/tasks/local_agent_tasks.py:95
msgid "starting"
msgstr "indítás"
#: vm/tasks/local_agent_tasks.py:101
#: vm/tasks/local_agent_tasks.py:113
msgid "start access server"
msgstr "távoli elérés indítása"
#: vm/tasks/local_agent_tasks.py:133
#: vm/tasks/local_agent_tasks.py:145
msgid "stopping"
msgstr "leállítás"
#: vm/tasks/local_agent_tasks.py:142
#: vm/tasks/local_agent_tasks.py:161
#, python-format
msgid "update to %(version)s"
msgstr "frissítés erre: %(version)s"
#: vm/tasks/local_agent_tasks.py:149
#: vm/tasks/local_agent_tasks.py:168
#, python-format
msgid "update agent to %(version)s"
msgstr "ügynökfrissítés erre: %(version)s"
......@@ -5116,6 +5343,9 @@ msgstr ""
msgid "x"
msgstr "x"
#~ msgid "Cores"
#~ msgstr "Magok száma"
#~ msgid "Mass delete complete, the following VM was deleted: %s."
#~ msgid_plural "Mass delete complete, the following VMs were deleted: %s."
#~ msgstr[0] "Sikeres tömeges törlés. A következő VM törlésre került: %s."
......@@ -5287,9 +5517,6 @@ msgstr "x"
#~ msgid "Saving instance as template!"
#~ msgstr "Példány mentése sablonként"
#~ msgid "Successfully created a new template!"
#~ msgstr "A sablon létrehozásra került."
#~ msgid "The template has been created, you can now add disks to it!"
#~ msgstr "A sablon létrehozásra került, hozzáadhat lemezeket."
......
......@@ -6,8 +6,8 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-08-29 09:21+0200\n"
"PO-Revision-Date: 2014-08-01 21:03+0200\n"
"POT-Creation-Date: 2014-09-03 18:49+0200\n"
"PO-Revision-Date: 2014-09-03 12:51+0200\n"
"Last-Translator: Mate Ory <ory.mate@ik.bme.hu>\n"
"Language-Team: Hungarian <cloud@ik.bme.hu>\n"
"Language: en_US\n"
......@@ -18,6 +18,22 @@ msgstr ""
"X-Generator: Lokalize 1.5\n"
#: dashboard/static/dashboard/dashboard.js:68
#: static_collected/all.047675ebf594.js:3443
#: static_collected/all.0aecd87e873a.js:3443
#: static_collected/all.0db607331718.js:3443
#: static_collected/all.146abee8fe99.js:3443
#: static_collected/all.24315fee0c8e.js:3443
#: static_collected/all.483236be7507.js:19
#: static_collected/all.73e18dd7e023.js:3443
#: static_collected/all.a650c949d06f.js:3443
#: static_collected/all.b66e942cdb56.js:3443
#: static_collected/all.f62aa30bd0a4.js:3443 static_collected/all.js:3443
#: static_collected/dashboard/dashboard.32a5b5729414.js:68
#: static_collected/dashboard/dashboard.32fd2a07ee32.js:68
#: static_collected/dashboard/dashboard.b96d0ea9ce41.js:68
#: static_collected/dashboard/dashboard.be8725cd91bf.js:68
#: static_collected/dashboard/dashboard.e740d80401b2.js:68
#: static_collected/dashboard/dashboard.fe0a2f126346.js:68
#: static_collected/dashboard/dashboard.js:68
msgid "Select an option to proceed!"
msgstr "Válasszon a folytatáshoz."
......@@ -25,6 +41,53 @@ msgstr "Válasszon a folytatáshoz."
#: dashboard/static/dashboard/dashboard.js:258
#: dashboard/static/dashboard/dashboard.js:306
#: dashboard/static/dashboard/dashboard.js:316
#: static_collected/all.047675ebf594.js:3633
#: static_collected/all.047675ebf594.js:3681
#: static_collected/all.047675ebf594.js:3691
#: static_collected/all.0aecd87e873a.js:3633
#: static_collected/all.0aecd87e873a.js:3681
#: static_collected/all.0aecd87e873a.js:3691
#: static_collected/all.0db607331718.js:3633
#: static_collected/all.0db607331718.js:3681
#: static_collected/all.0db607331718.js:3691
#: static_collected/all.146abee8fe99.js:3633
#: static_collected/all.146abee8fe99.js:3681
#: static_collected/all.146abee8fe99.js:3691
#: static_collected/all.24315fee0c8e.js:3633
#: static_collected/all.24315fee0c8e.js:3681
#: static_collected/all.24315fee0c8e.js:3691
#: static_collected/all.483236be7507.js:19
#: static_collected/all.73e18dd7e023.js:3633
#: static_collected/all.73e18dd7e023.js:3681
#: static_collected/all.73e18dd7e023.js:3691
#: static_collected/all.a650c949d06f.js:3633
#: static_collected/all.a650c949d06f.js:3681
#: static_collected/all.a650c949d06f.js:3691
#: static_collected/all.b66e942cdb56.js:3633
#: static_collected/all.b66e942cdb56.js:3681
#: static_collected/all.b66e942cdb56.js:3691
#: static_collected/all.f62aa30bd0a4.js:3633
#: static_collected/all.f62aa30bd0a4.js:3681
#: static_collected/all.f62aa30bd0a4.js:3691 static_collected/all.js:3633
#: static_collected/all.js.c:3681 static_collected/all.js:3691
#: static_collected/dashboard/dashboard.32a5b5729414.js:258
#: static_collected/dashboard/dashboard.32a5b5729414.js:306
#: static_collected/dashboard/dashboard.32a5b5729414.js:316
#: static_collected/dashboard/dashboard.32fd2a07ee32.js:258
#: static_collected/dashboard/dashboard.32fd2a07ee32.js:306
#: static_collected/dashboard/dashboard.32fd2a07ee32.js:316
#: static_collected/dashboard/dashboard.b96d0ea9ce41.js:258
#: static_collected/dashboard/dashboard.b96d0ea9ce41.js:306
#: static_collected/dashboard/dashboard.b96d0ea9ce41.js:316
#: static_collected/dashboard/dashboard.be8725cd91bf.js:258
#: static_collected/dashboard/dashboard.be8725cd91bf.js:306
#: static_collected/dashboard/dashboard.be8725cd91bf.js:316
#: static_collected/dashboard/dashboard.e740d80401b2.js:258
#: static_collected/dashboard/dashboard.e740d80401b2.js:306
#: static_collected/dashboard/dashboard.e740d80401b2.js:316
#: static_collected/dashboard/dashboard.fe0a2f126346.js:258
#: static_collected/dashboard/dashboard.fe0a2f126346.js:306
#: static_collected/dashboard/dashboard.fe0a2f126346.js:316
#: static_collected/dashboard/dashboard.js:258
#: static_collected/dashboard/dashboard.js:306
#: static_collected/dashboard/dashboard.js:316
......@@ -32,48 +95,173 @@ msgid "No result"
msgstr "Nincs eredmény"
#: dashboard/static/dashboard/profile.js:18
#: static_collected/all.047675ebf594.js:4459
#: static_collected/all.0aecd87e873a.js:4458
#: static_collected/all.0db607331718.js:4435
#: static_collected/all.146abee8fe99.js:4459
#: static_collected/all.24315fee0c8e.js:4458
#: static_collected/all.483236be7507.js:21
#: static_collected/all.73e18dd7e023.js:4435
#: static_collected/all.a650c949d06f.js:4458
#: static_collected/all.b66e942cdb56.js:4458
#: static_collected/all.f62aa30bd0a4.js:4459 static_collected/all.js:4435
#: static_collected/dashboard/profile.333ac16a5ce1.js:18
#: static_collected/dashboard/profile.b7bd994913eb.js:18
#: static_collected/dashboard/profile.js:18
msgid "You have no permission to change this profile."
msgstr "Nincs jogosultsága a profil módosításához."
#: dashboard/static/dashboard/profile.js:20
#: static_collected/all.047675ebf594.js:4461
#: static_collected/all.0aecd87e873a.js:4460
#: static_collected/all.0db607331718.js:4437
#: static_collected/all.146abee8fe99.js:4461
#: static_collected/all.24315fee0c8e.js:4460
#: static_collected/all.483236be7507.js:21
#: static_collected/all.73e18dd7e023.js:4437
#: static_collected/all.a650c949d06f.js:4460
#: static_collected/all.b66e942cdb56.js:4460
#: static_collected/all.f62aa30bd0a4.js:4461 static_collected/all.js:4437
#: static_collected/dashboard/profile.333ac16a5ce1.js:20
#: static_collected/dashboard/profile.b7bd994913eb.js:20
#: static_collected/dashboard/profile.js:20
msgid "Unknown error."
msgstr "Ismeretlen hiba."
#: dashboard/static/dashboard/vm-create.js:111
#: dashboard/static/dashboard/vm-create.js:174
#: static_collected/all.047675ebf594.js:4813
#: static_collected/all.047675ebf594.js:4876
#: static_collected/all.0aecd87e873a.js:4883
#: static_collected/all.0aecd87e873a.js:4946
#: static_collected/all.0db607331718.js:4789
#: static_collected/all.0db607331718.js:4852
#: static_collected/all.146abee8fe99.js:4813
#: static_collected/all.146abee8fe99.js:4876
#: static_collected/all.24315fee0c8e.js:4812
#: static_collected/all.24315fee0c8e.js:4875
#: static_collected/all.483236be7507.js:2
#: static_collected/all.73e18dd7e023.js:4789
#: static_collected/all.73e18dd7e023.js:4852
#: static_collected/all.a650c949d06f.js:4812
#: static_collected/all.a650c949d06f.js:4875
#: static_collected/all.b66e942cdb56.js:4812
#: static_collected/all.b66e942cdb56.js:4875
#: static_collected/all.f62aa30bd0a4.js:4813
#: static_collected/all.f62aa30bd0a4.js:4876 static_collected/all.js:4789
#: static_collected/all.js.c:4852
#: static_collected/dashboard/vm-create.1a1f6dae3556.js:111
#: static_collected/dashboard/vm-create.1a1f6dae3556.js:174
#: static_collected/dashboard/vm-create.7562c27e19a2.js:111
#: static_collected/dashboard/vm-create.7562c27e19a2.js:174
#: static_collected/dashboard/vm-create.js:111
#: static_collected/dashboard/vm-create.js:174
msgid "No more networks."
msgstr "Nincs több hálózat."
#: dashboard/static/dashboard/vm-create.js:143
#: static_collected/all.047675ebf594.js:4845
#: static_collected/all.0aecd87e873a.js:4915
#: static_collected/all.0db607331718.js:4821
#: static_collected/all.146abee8fe99.js:4845
#: static_collected/all.24315fee0c8e.js:4844
#: static_collected/all.483236be7507.js:2
#: static_collected/all.73e18dd7e023.js:4821
#: static_collected/all.a650c949d06f.js:4844
#: static_collected/all.b66e942cdb56.js:4844
#: static_collected/all.f62aa30bd0a4.js:4845 static_collected/all.js:4821
#: static_collected/dashboard/vm-create.1a1f6dae3556.js:143
#: static_collected/dashboard/vm-create.7562c27e19a2.js:143
#: static_collected/dashboard/vm-create.js:143
msgid "Not added to any network"
msgstr "Nincs hálózathoz adva"
#: dashboard/static/dashboard/vm-details.js:115
#: static_collected/dashboard/vm-details.js:115
msgid "Hide password"
msgstr "Jelszó rejtése"
#: dashboard/static/dashboard/vm-details.js:119
#: static_collected/dashboard/vm-details.js:119
msgid "Show password"
msgstr "Jelszó megjelenítése"
#: dashboard/static/dashboard/vm-tour.js:20
#: static_collected/vm-detail.09737c69abc3.js:5853
#: static_collected/vm-detail.15d710d8ccf0.js:6389
#: static_collected/vm-detail.234990ca6ec1.js:6962
#: static_collected/vm-detail.47b1d21da259.js:5853
#: static_collected/vm-detail.9e1734ade019.js:5854
#: static_collected/vm-detail.c47949114749.js:6962
#: static_collected/vm-detail.e3f398067c8a.js:6891
#: static_collected/vm-detail.e81fe84bf4c0.js:9
#: static_collected/vm-detail.js:6389
#: static_collected/dashboard/vm-tour.1562cc89a659.js:20
#: static_collected/dashboard/vm-tour.7b4cf596f543.js:20
#: static_collected/dashboard/vm-tour.js:20
msgid "Prev"
msgstr "Vissza"
#: dashboard/static/dashboard/vm-tour.js:22
#: static_collected/vm-detail.09737c69abc3.js:5855
#: static_collected/vm-detail.15d710d8ccf0.js:6391
#: static_collected/vm-detail.234990ca6ec1.js:6964
#: static_collected/vm-detail.47b1d21da259.js:5855
#: static_collected/vm-detail.9e1734ade019.js:5856
#: static_collected/vm-detail.c47949114749.js:6964
#: static_collected/vm-detail.e3f398067c8a.js:6893
#: static_collected/vm-detail.e81fe84bf4c0.js:9
#: static_collected/vm-detail.js:6391
#: static_collected/dashboard/vm-tour.1562cc89a659.js:22
#: static_collected/dashboard/vm-tour.7b4cf596f543.js:22
#: static_collected/dashboard/vm-tour.js:22
msgid "Next"
msgstr "Tovább"
#: dashboard/static/dashboard/vm-tour.js:26
#: static_collected/vm-detail.09737c69abc3.js:5859
#: static_collected/vm-detail.15d710d8ccf0.js:6395
#: static_collected/vm-detail.234990ca6ec1.js:6968
#: static_collected/vm-detail.47b1d21da259.js:5859
#: static_collected/vm-detail.9e1734ade019.js:5860
#: static_collected/vm-detail.c47949114749.js:6968
#: static_collected/vm-detail.e3f398067c8a.js:6897
#: static_collected/vm-detail.e81fe84bf4c0.js:9
#: static_collected/vm-detail.js:6395
#: static_collected/dashboard/vm-tour.1562cc89a659.js:26
#: static_collected/dashboard/vm-tour.7b4cf596f543.js:26
#: static_collected/dashboard/vm-tour.js:26
msgid "End tour"
msgstr "Befejezés"
#: dashboard/static/dashboard/vm-tour.js:33
#: static_collected/vm-detail.09737c69abc3.js:5866
#: static_collected/vm-detail.15d710d8ccf0.js:6402
#: static_collected/vm-detail.234990ca6ec1.js:6975
#: static_collected/vm-detail.47b1d21da259.js:5866
#: static_collected/vm-detail.9e1734ade019.js:5867
#: static_collected/vm-detail.c47949114749.js:6975
#: static_collected/vm-detail.e3f398067c8a.js:6904
#: static_collected/vm-detail.e81fe84bf4c0.js:9
#: static_collected/vm-detail.js:6402
#: static_collected/dashboard/vm-tour.1562cc89a659.js:33
#: static_collected/dashboard/vm-tour.7b4cf596f543.js:33
#: static_collected/dashboard/vm-tour.js:33
msgid "Template Tutorial Tour"
msgstr "Sablon-kalauz"
#: dashboard/static/dashboard/vm-tour.js:34
#: static_collected/vm-detail.09737c69abc3.js:5867
#: static_collected/vm-detail.15d710d8ccf0.js:6403
#: static_collected/vm-detail.234990ca6ec1.js:6976
#: static_collected/vm-detail.47b1d21da259.js:5867
#: static_collected/vm-detail.9e1734ade019.js:5868
#: static_collected/vm-detail.c47949114749.js:6976
#: static_collected/vm-detail.e3f398067c8a.js:6905
#: static_collected/vm-detail.e81fe84bf4c0.js:9
#: static_collected/vm-detail.js:6403
#: static_collected/dashboard/vm-tour.1562cc89a659.js:34
#: static_collected/dashboard/vm-tour.7b4cf596f543.js:34
#: static_collected/dashboard/vm-tour.js:34
msgid ""
"Welcome to the template tutorial. In this quick tour, we gonna show you how "
......@@ -83,6 +271,17 @@ msgstr ""
"lépéseket."
#: dashboard/static/dashboard/vm-tour.js:35
#: static_collected/vm-detail.09737c69abc3.js:5868
#: static_collected/vm-detail.15d710d8ccf0.js:6404
#: static_collected/vm-detail.234990ca6ec1.js:6977
#: static_collected/vm-detail.47b1d21da259.js:5868
#: static_collected/vm-detail.9e1734ade019.js:5869
#: static_collected/vm-detail.c47949114749.js:6977
#: static_collected/vm-detail.e3f398067c8a.js:6906
#: static_collected/vm-detail.e81fe84bf4c0.js:9
#: static_collected/vm-detail.js:6404
#: static_collected/dashboard/vm-tour.1562cc89a659.js:35
#: static_collected/dashboard/vm-tour.7b4cf596f543.js:35
#: static_collected/dashboard/vm-tour.js:35
msgid ""
"For the next tour step press the \"Next\" button or the right arrow (or "
......@@ -92,6 +291,16 @@ msgstr ""
"nyílbillentyűket."
#: dashboard/static/dashboard/vm-tour.js:36
#: static_collected/vm-detail.09737c69abc3.js:5869
#: static_collected/vm-detail.15d710d8ccf0.js:6405
#: static_collected/vm-detail.234990ca6ec1.js:6978
#: static_collected/vm-detail.47b1d21da259.js:5869
#: static_collected/vm-detail.9e1734ade019.js:5870
#: static_collected/vm-detail.c47949114749.js:6978
#: static_collected/vm-detail.e3f398067c8a.js:6907
#: static_collected/vm-detail.js:6405
#: static_collected/dashboard/vm-tour.1562cc89a659.js:36
#: static_collected/dashboard/vm-tour.7b4cf596f543.js:36
#: static_collected/dashboard/vm-tour.js:36
msgid ""
"During the tour please don't try the functions because it may lead to "
......@@ -99,11 +308,33 @@ msgid ""
msgstr "A túra során még ne próbálja ki a bemutatott funkciókat."
#: dashboard/static/dashboard/vm-tour.js:45
#: static_collected/vm-detail.09737c69abc3.js:5878
#: static_collected/vm-detail.15d710d8ccf0.js:6414
#: static_collected/vm-detail.234990ca6ec1.js:6987
#: static_collected/vm-detail.47b1d21da259.js:5878
#: static_collected/vm-detail.9e1734ade019.js:5879
#: static_collected/vm-detail.c47949114749.js:6987
#: static_collected/vm-detail.e3f398067c8a.js:6916
#: static_collected/vm-detail.e81fe84bf4c0.js:9
#: static_collected/vm-detail.js:6414
#: static_collected/dashboard/vm-tour.1562cc89a659.js:45
#: static_collected/dashboard/vm-tour.7b4cf596f543.js:45
#: static_collected/dashboard/vm-tour.js:45
msgid "Home tab"
msgstr "Kezdőoldal"
#: dashboard/static/dashboard/vm-tour.js:46
#: static_collected/vm-detail.09737c69abc3.js:5879
#: static_collected/vm-detail.15d710d8ccf0.js:6415
#: static_collected/vm-detail.234990ca6ec1.js:6988
#: static_collected/vm-detail.47b1d21da259.js:5879
#: static_collected/vm-detail.9e1734ade019.js:5880
#: static_collected/vm-detail.c47949114749.js:6988
#: static_collected/vm-detail.e3f398067c8a.js:6917
#: static_collected/vm-detail.e81fe84bf4c0.js:9
#: static_collected/vm-detail.js:6415
#: static_collected/dashboard/vm-tour.1562cc89a659.js:46
#: static_collected/dashboard/vm-tour.7b4cf596f543.js:46
#: static_collected/dashboard/vm-tour.js:46
msgid ""
"In this tab you can tag your virtual machine and modify the name and "
......@@ -113,11 +344,33 @@ msgstr ""
"leírását."
#: dashboard/static/dashboard/vm-tour.js:55
#: static_collected/vm-detail.09737c69abc3.js:5888
#: static_collected/vm-detail.15d710d8ccf0.js:6424
#: static_collected/vm-detail.234990ca6ec1.js:6997
#: static_collected/vm-detail.47b1d21da259.js:5888
#: static_collected/vm-detail.9e1734ade019.js:5889
#: static_collected/vm-detail.c47949114749.js:6997
#: static_collected/vm-detail.e3f398067c8a.js:6926
#: static_collected/vm-detail.e81fe84bf4c0.js:9
#: static_collected/vm-detail.js:6424
#: static_collected/dashboard/vm-tour.1562cc89a659.js:55
#: static_collected/dashboard/vm-tour.7b4cf596f543.js:55
#: static_collected/dashboard/vm-tour.js:55
msgid "Resources tab"
msgstr "Erőforrások lap"
#: dashboard/static/dashboard/vm-tour.js:58
#: static_collected/vm-detail.09737c69abc3.js:5891
#: static_collected/vm-detail.15d710d8ccf0.js:6427
#: static_collected/vm-detail.234990ca6ec1.js:7000
#: static_collected/vm-detail.47b1d21da259.js:5891
#: static_collected/vm-detail.9e1734ade019.js:5892
#: static_collected/vm-detail.c47949114749.js:7000
#: static_collected/vm-detail.e3f398067c8a.js:6929
#: static_collected/vm-detail.e81fe84bf4c0.js:9
#: static_collected/vm-detail.js:6427
#: static_collected/dashboard/vm-tour.1562cc89a659.js:58
#: static_collected/dashboard/vm-tour.7b4cf596f543.js:58
#: static_collected/dashboard/vm-tour.js:58
msgid ""
"On the resources tab you can edit the CPU/RAM options and add/remove disks!"
......@@ -126,46 +379,145 @@ msgstr ""
"hozzáadhat és törölhet lemezeket."
#: dashboard/static/dashboard/vm-tour.js:68
#: static_collected/vm-detail.09737c69abc3.js:5901
#: static_collected/vm-detail.15d710d8ccf0.js:6437
#: static_collected/vm-detail.234990ca6ec1.js:7010
#: static_collected/vm-detail.47b1d21da259.js:5901
#: static_collected/vm-detail.9e1734ade019.js:5902
#: static_collected/vm-detail.c47949114749.js:7010
#: static_collected/vm-detail.e3f398067c8a.js:6939
#: static_collected/vm-detail.e81fe84bf4c0.js:9
#: static_collected/vm-detail.js:6437
#: static_collected/dashboard/vm-tour.1562cc89a659.js:68
#: static_collected/dashboard/vm-tour.7b4cf596f543.js:68
#: static_collected/dashboard/vm-tour.js:68
msgid "Resources"
msgstr "Erőforrások"
#: dashboard/static/dashboard/vm-tour.js:69
#: static_collected/vm-detail.09737c69abc3.js:5902
#: static_collected/vm-detail.15d710d8ccf0.js:6438
#: static_collected/vm-detail.234990ca6ec1.js:7011
#: static_collected/vm-detail.47b1d21da259.js:5902
#: static_collected/vm-detail.9e1734ade019.js:5903
#: static_collected/vm-detail.c47949114749.js:7011
#: static_collected/vm-detail.e3f398067c8a.js:6940
#: static_collected/vm-detail.e81fe84bf4c0.js:9
#: static_collected/vm-detail.js:6438
#: static_collected/dashboard/vm-tour.1562cc89a659.js:69
#: static_collected/dashboard/vm-tour.7b4cf596f543.js:69
#: static_collected/dashboard/vm-tour.js:69
msgid "CPU priority"
msgstr "CPU prioritás"
#: dashboard/static/dashboard/vm-tour.js:69
#: static_collected/vm-detail.09737c69abc3.js:5902
#: static_collected/vm-detail.15d710d8ccf0.js:6438
#: static_collected/vm-detail.234990ca6ec1.js:7011
#: static_collected/vm-detail.47b1d21da259.js:5902
#: static_collected/vm-detail.9e1734ade019.js:5903
#: static_collected/vm-detail.c47949114749.js:7011
#: static_collected/vm-detail.e3f398067c8a.js:6940
#: static_collected/vm-detail.e81fe84bf4c0.js:9
#: static_collected/vm-detail.js:6438
#: static_collected/dashboard/vm-tour.1562cc89a659.js:69
#: static_collected/dashboard/vm-tour.7b4cf596f543.js:69
#: static_collected/dashboard/vm-tour.js:69
msgid "higher is better"
msgstr "a nagyobb érték a jobb"
#: dashboard/static/dashboard/vm-tour.js:70
#: static_collected/vm-detail.09737c69abc3.js:5903
#: static_collected/vm-detail.15d710d8ccf0.js:6439
#: static_collected/vm-detail.234990ca6ec1.js:7012
#: static_collected/vm-detail.47b1d21da259.js:5903
#: static_collected/vm-detail.9e1734ade019.js:5904
#: static_collected/vm-detail.c47949114749.js:7012
#: static_collected/vm-detail.e3f398067c8a.js:6941
#: static_collected/vm-detail.e81fe84bf4c0.js:9
#: static_collected/vm-detail.js:6439
#: static_collected/dashboard/vm-tour.1562cc89a659.js:70
#: static_collected/dashboard/vm-tour.7b4cf596f543.js:70
#: static_collected/dashboard/vm-tour.js:70
msgid "CPU count"
msgstr "CPU-k száma"
#: dashboard/static/dashboard/vm-tour.js:70
#: static_collected/vm-detail.09737c69abc3.js:5903
#: static_collected/vm-detail.15d710d8ccf0.js:6439
#: static_collected/vm-detail.234990ca6ec1.js:7012
#: static_collected/vm-detail.47b1d21da259.js:5903
#: static_collected/vm-detail.9e1734ade019.js:5904
#: static_collected/vm-detail.c47949114749.js:7012
#: static_collected/vm-detail.e3f398067c8a.js:6941
#: static_collected/vm-detail.e81fe84bf4c0.js:9
#: static_collected/vm-detail.js:6439
#: static_collected/dashboard/vm-tour.1562cc89a659.js:70
#: static_collected/dashboard/vm-tour.7b4cf596f543.js:70
#: static_collected/dashboard/vm-tour.js:70
msgid "number of CPU cores."
msgstr "A CPU-magok száma."
#: dashboard/static/dashboard/vm-tour.js:71
#: static_collected/vm-detail.09737c69abc3.js:5904
#: static_collected/vm-detail.15d710d8ccf0.js:6440
#: static_collected/vm-detail.234990ca6ec1.js:7013
#: static_collected/vm-detail.47b1d21da259.js:5904
#: static_collected/vm-detail.9e1734ade019.js:5905
#: static_collected/vm-detail.c47949114749.js:7013
#: static_collected/vm-detail.e3f398067c8a.js:6942
#: static_collected/vm-detail.e81fe84bf4c0.js:9
#: static_collected/vm-detail.js:6440
#: static_collected/dashboard/vm-tour.1562cc89a659.js:71
#: static_collected/dashboard/vm-tour.7b4cf596f543.js:71
#: static_collected/dashboard/vm-tour.js:71
msgid "RAM amount"
msgstr "RAM mennyiség"
#: dashboard/static/dashboard/vm-tour.js:71
#: static_collected/vm-detail.09737c69abc3.js:5904
#: static_collected/vm-detail.15d710d8ccf0.js:6440
#: static_collected/vm-detail.234990ca6ec1.js:7013
#: static_collected/vm-detail.47b1d21da259.js:5904
#: static_collected/vm-detail.9e1734ade019.js:5905
#: static_collected/vm-detail.c47949114749.js:7013
#: static_collected/vm-detail.e3f398067c8a.js:6942
#: static_collected/vm-detail.e81fe84bf4c0.js:9
#: static_collected/vm-detail.js:6440
#: static_collected/dashboard/vm-tour.1562cc89a659.js:71
#: static_collected/dashboard/vm-tour.7b4cf596f543.js:71
#: static_collected/dashboard/vm-tour.js:71
msgid "amount of RAM."
msgstr "a memória mennyisége."
#: dashboard/static/dashboard/vm-tour.js:81
#: static_collected/vm-detail.09737c69abc3.js:5914
#: static_collected/vm-detail.15d710d8ccf0.js:6450
#: static_collected/vm-detail.234990ca6ec1.js:7023
#: static_collected/vm-detail.47b1d21da259.js:5914
#: static_collected/vm-detail.9e1734ade019.js:5915
#: static_collected/vm-detail.c47949114749.js:7023
#: static_collected/vm-detail.e3f398067c8a.js:6952
#: static_collected/vm-detail.e81fe84bf4c0.js:9
#: static_collected/vm-detail.js:6450
#: static_collected/dashboard/vm-tour.1562cc89a659.js:81
#: static_collected/dashboard/vm-tour.7b4cf596f543.js:81
#: static_collected/dashboard/vm-tour.js:81
msgid "Disks"
msgstr "Lemezek"
#: dashboard/static/dashboard/vm-tour.js:82
#: static_collected/vm-detail.09737c69abc3.js:5915
#: static_collected/vm-detail.15d710d8ccf0.js:6451
#: static_collected/vm-detail.234990ca6ec1.js:7024
#: static_collected/vm-detail.47b1d21da259.js:5915
#: static_collected/vm-detail.9e1734ade019.js:5916
#: static_collected/vm-detail.c47949114749.js:7024
#: static_collected/vm-detail.e3f398067c8a.js:6953
#: static_collected/vm-detail.e81fe84bf4c0.js:9
#: static_collected/vm-detail.js:6451
#: static_collected/dashboard/vm-tour.1562cc89a659.js:82
#: static_collected/dashboard/vm-tour.7b4cf596f543.js:82
#: static_collected/dashboard/vm-tour.js:82
msgid ""
"You can add empty disks, download new ones and remove existing ones here."
......@@ -174,41 +526,129 @@ msgstr ""
"meglévőket."
#: dashboard/static/dashboard/vm-tour.js:92
#: static_collected/vm-detail.09737c69abc3.js:5925
#: static_collected/vm-detail.15d710d8ccf0.js:6461
#: static_collected/vm-detail.234990ca6ec1.js:7034
#: static_collected/vm-detail.47b1d21da259.js:5925
#: static_collected/vm-detail.9e1734ade019.js:5926
#: static_collected/vm-detail.c47949114749.js:7034
#: static_collected/vm-detail.e3f398067c8a.js:6963
#: static_collected/vm-detail.e81fe84bf4c0.js:10
#: static_collected/vm-detail.js:6461
#: static_collected/dashboard/vm-tour.1562cc89a659.js:92
#: static_collected/dashboard/vm-tour.7b4cf596f543.js:92
#: static_collected/dashboard/vm-tour.js:92
msgid "Network tab"
msgstr "Hálózat lap"
#: dashboard/static/dashboard/vm-tour.js:93
#: static_collected/vm-detail.09737c69abc3.js:5926
#: static_collected/vm-detail.15d710d8ccf0.js:6462
#: static_collected/vm-detail.234990ca6ec1.js:7035
#: static_collected/vm-detail.47b1d21da259.js:5926
#: static_collected/vm-detail.9e1734ade019.js:5927
#: static_collected/vm-detail.c47949114749.js:7035
#: static_collected/vm-detail.e3f398067c8a.js:6964
#: static_collected/vm-detail.e81fe84bf4c0.js:10
#: static_collected/vm-detail.js:6462
#: static_collected/dashboard/vm-tour.1562cc89a659.js:93
#: static_collected/dashboard/vm-tour.7b4cf596f543.js:93
#: static_collected/dashboard/vm-tour.js:93
msgid "You can add new network interfaces or remove existing ones here."
msgstr "Hozzáadhat új hálózati interfészeket, vagy törölheti a meglévőket."
#: dashboard/static/dashboard/vm-tour.js:102
#: static_collected/vm-detail.09737c69abc3.js:5935
#: static_collected/vm-detail.15d710d8ccf0.js:6471
#: static_collected/vm-detail.234990ca6ec1.js:7044
#: static_collected/vm-detail.47b1d21da259.js:5935
#: static_collected/vm-detail.9e1734ade019.js:5936
#: static_collected/vm-detail.c47949114749.js:7044
#: static_collected/vm-detail.e3f398067c8a.js:6973
#: static_collected/vm-detail.e81fe84bf4c0.js:10
#: static_collected/vm-detail.js:6471
#: static_collected/dashboard/vm-tour.1562cc89a659.js:102
#: static_collected/dashboard/vm-tour.7b4cf596f543.js:102
#: static_collected/dashboard/vm-tour.js:102
msgid "Deploy"
msgstr "Indítás"
#: dashboard/static/dashboard/vm-tour.js:105
#: static_collected/vm-detail.09737c69abc3.js:5938
#: static_collected/vm-detail.15d710d8ccf0.js:6474
#: static_collected/vm-detail.234990ca6ec1.js:7047
#: static_collected/vm-detail.47b1d21da259.js:5938
#: static_collected/vm-detail.9e1734ade019.js:5939
#: static_collected/vm-detail.c47949114749.js:7047
#: static_collected/vm-detail.e3f398067c8a.js:6976
#: static_collected/vm-detail.e81fe84bf4c0.js:10
#: static_collected/vm-detail.js:6474
#: static_collected/dashboard/vm-tour.1562cc89a659.js:105
#: static_collected/dashboard/vm-tour.7b4cf596f543.js:105
#: static_collected/dashboard/vm-tour.js:105
msgid "Deploy the virtual machine."
msgstr "A virtuális gép elindítása."
#: dashboard/static/dashboard/vm-tour.js:110
#: static_collected/vm-detail.09737c69abc3.js:5943
#: static_collected/vm-detail.15d710d8ccf0.js:6479
#: static_collected/vm-detail.234990ca6ec1.js:7052
#: static_collected/vm-detail.47b1d21da259.js:5943
#: static_collected/vm-detail.9e1734ade019.js:5944
#: static_collected/vm-detail.c47949114749.js:7052
#: static_collected/vm-detail.e3f398067c8a.js:6981
#: static_collected/vm-detail.e81fe84bf4c0.js:10
#: static_collected/vm-detail.js:6479
#: static_collected/dashboard/vm-tour.1562cc89a659.js:110
#: static_collected/dashboard/vm-tour.7b4cf596f543.js:110
#: static_collected/dashboard/vm-tour.js:110
msgid "Connect"
msgstr "Csatlakozás"
#: dashboard/static/dashboard/vm-tour.js:113
#: static_collected/vm-detail.09737c69abc3.js:5946
#: static_collected/vm-detail.15d710d8ccf0.js:6482
#: static_collected/vm-detail.234990ca6ec1.js:7055
#: static_collected/vm-detail.47b1d21da259.js:5946
#: static_collected/vm-detail.9e1734ade019.js:5947
#: static_collected/vm-detail.c47949114749.js:7055
#: static_collected/vm-detail.e3f398067c8a.js:6984
#: static_collected/vm-detail.e81fe84bf4c0.js:10
#: static_collected/vm-detail.js:6482
#: static_collected/dashboard/vm-tour.1562cc89a659.js:113
#: static_collected/dashboard/vm-tour.7b4cf596f543.js:113
#: static_collected/dashboard/vm-tour.js:113
msgid "Use the connection string or connect with your choice of client!"
msgstr "Használja a megadott parancsot, vagy kedvenc kliensét."
#: dashboard/static/dashboard/vm-tour.js:120
#: static_collected/vm-detail.09737c69abc3.js:5953
#: static_collected/vm-detail.15d710d8ccf0.js:6489
#: static_collected/vm-detail.234990ca6ec1.js:7062
#: static_collected/vm-detail.47b1d21da259.js:5953
#: static_collected/vm-detail.9e1734ade019.js:5954
#: static_collected/vm-detail.c47949114749.js:7062
#: static_collected/vm-detail.e3f398067c8a.js:6991
#: static_collected/vm-detail.e81fe84bf4c0.js:10
#: static_collected/vm-detail.js:6489
#: static_collected/dashboard/vm-tour.1562cc89a659.js:120
#: static_collected/dashboard/vm-tour.7b4cf596f543.js:120
#: static_collected/dashboard/vm-tour.js:120
msgid "Customize the virtual machine"
msgstr "Szabja testre a gépet"
#: dashboard/static/dashboard/vm-tour.js:121
#: static_collected/vm-detail.09737c69abc3.js:5954
#: static_collected/vm-detail.15d710d8ccf0.js:6490
#: static_collected/vm-detail.234990ca6ec1.js:7063
#: static_collected/vm-detail.47b1d21da259.js:5954
#: static_collected/vm-detail.9e1734ade019.js:5955
#: static_collected/vm-detail.c47949114749.js:7063
#: static_collected/vm-detail.e3f398067c8a.js:6992
#: static_collected/vm-detail.e81fe84bf4c0.js:10
#: static_collected/vm-detail.js:6490
#: static_collected/dashboard/vm-tour.1562cc89a659.js:121
#: static_collected/dashboard/vm-tour.7b4cf596f543.js:121
#: static_collected/dashboard/vm-tour.js:121
msgid ""
"After you have connected to the virtual machine do your modifications then "
......@@ -218,11 +658,33 @@ msgstr ""
"ki."
#: dashboard/static/dashboard/vm-tour.js:126
#: static_collected/vm-detail.09737c69abc3.js:5959
#: static_collected/vm-detail.15d710d8ccf0.js:6495
#: static_collected/vm-detail.234990ca6ec1.js:7068
#: static_collected/vm-detail.47b1d21da259.js:5959
#: static_collected/vm-detail.9e1734ade019.js:5960
#: static_collected/vm-detail.c47949114749.js:7068
#: static_collected/vm-detail.e3f398067c8a.js:6997
#: static_collected/vm-detail.e81fe84bf4c0.js:10
#: static_collected/vm-detail.js:6495
#: static_collected/dashboard/vm-tour.1562cc89a659.js:126
#: static_collected/dashboard/vm-tour.7b4cf596f543.js:126
#: static_collected/dashboard/vm-tour.js:126
msgid "Save as"
msgstr "Mentés sablonként"
#: dashboard/static/dashboard/vm-tour.js:129
#: static_collected/vm-detail.09737c69abc3.js:5962
#: static_collected/vm-detail.15d710d8ccf0.js:6498
#: static_collected/vm-detail.234990ca6ec1.js:7071
#: static_collected/vm-detail.47b1d21da259.js:5962
#: static_collected/vm-detail.9e1734ade019.js:5963
#: static_collected/vm-detail.c47949114749.js:7071
#: static_collected/vm-detail.e3f398067c8a.js:7000
#: static_collected/vm-detail.e81fe84bf4c0.js:10
#: static_collected/vm-detail.js:6498
#: static_collected/dashboard/vm-tour.1562cc89a659.js:129
#: static_collected/dashboard/vm-tour.7b4cf596f543.js:129
#: static_collected/dashboard/vm-tour.js:129
msgid ""
"Press the \"Save as template\" button and wait until the activity finishes."
......@@ -231,18 +693,50 @@ msgstr ""
"elkészül."
#: dashboard/static/dashboard/vm-tour.js:135
#: static_collected/vm-detail.09737c69abc3.js:5968
#: static_collected/vm-detail.15d710d8ccf0.js:6504
#: static_collected/vm-detail.234990ca6ec1.js:7077
#: static_collected/vm-detail.47b1d21da259.js:5968
#: static_collected/vm-detail.9e1734ade019.js:5969
#: static_collected/vm-detail.c47949114749.js:7077
#: static_collected/vm-detail.e3f398067c8a.js:7006
#: static_collected/vm-detail.e81fe84bf4c0.js:10
#: static_collected/vm-detail.js:6504
#: static_collected/dashboard/vm-tour.1562cc89a659.js:135
#: static_collected/dashboard/vm-tour.7b4cf596f543.js:135
#: static_collected/dashboard/vm-tour.js:135
msgid "Finish"
msgstr "Befejezés"
#: dashboard/static/dashboard/vm-tour.js:138
#: static_collected/vm-detail.09737c69abc3.js:5971
#: static_collected/vm-detail.15d710d8ccf0.js:6507
#: static_collected/vm-detail.234990ca6ec1.js:7080
#: static_collected/vm-detail.47b1d21da259.js:5971
#: static_collected/vm-detail.9e1734ade019.js:5972
#: static_collected/vm-detail.c47949114749.js:7080
#: static_collected/vm-detail.e3f398067c8a.js:7009
#: static_collected/vm-detail.e81fe84bf4c0.js:10
#: static_collected/vm-detail.js:6507
#: static_collected/dashboard/vm-tour.1562cc89a659.js:138
#: static_collected/dashboard/vm-tour.7b4cf596f543.js:138
#: static_collected/dashboard/vm-tour.js:138
msgid ""
"This is the last message, if something is not clear you can do the the tour "
"again!"
msgstr "A túra véget ért. Ha valami nem érthető, újrakezdheti az útmutatót."
#: network/static/js/host.js:10 static_collected/js/host.js:10
#: network/static/js/host.js:10 static_collected/all.047675ebf594.js:5239
#: static_collected/all.0aecd87e873a.js:5309
#: static_collected/all.0db607331718.js:5215
#: static_collected/all.146abee8fe99.js:5239
#: static_collected/all.24315fee0c8e.js:5238
#: static_collected/all.483236be7507.js:22
#: static_collected/all.73e18dd7e023.js:5215
#: static_collected/all.a650c949d06f.js:5238
#: static_collected/all.b66e942cdb56.js:5238
#: static_collected/all.f62aa30bd0a4.js:5239 static_collected/all.js:5215
#: static_collected/js/host.e1b01efa0e67.js:10 static_collected/js/host.js:10
msgid ""
"Are you sure you want to remove host group <strong>\"%(group)s\"</strong> "
"from <strong>\"%(host)s\"</strong>?"
......@@ -250,32 +744,113 @@ msgstr ""
"Biztosan törli a(z)<strong>„%(host)s”</strong> gépet a(z) "
"<strong>„%(group)s”</strong> gépcsoportból?"
#: network/static/js/host.js:13 static_collected/js/host.js:13
#: network/static/js/host.js:13 static_collected/all.047675ebf594.js:5242
#: static_collected/all.0aecd87e873a.js:5312
#: static_collected/all.0db607331718.js:5218
#: static_collected/all.146abee8fe99.js:5242
#: static_collected/all.24315fee0c8e.js:5241
#: static_collected/all.483236be7507.js:22
#: static_collected/all.73e18dd7e023.js:5218
#: static_collected/all.a650c949d06f.js:5241
#: static_collected/all.b66e942cdb56.js:5241
#: static_collected/all.f62aa30bd0a4.js:5242 static_collected/all.js:5218
#: static_collected/js/host.e1b01efa0e67.js:13 static_collected/js/host.js:13
msgid "Are you sure you want to delete this rule?"
msgstr "Biztosan törli ezt a szabályt?"
#: network/static/js/host.js:20 network/static/js/switch-port.js:14
#: static_collected/all.047675ebf594.js:5249
#: static_collected/all.047675ebf594.js:5347
#: static_collected/all.0aecd87e873a.js:5319
#: static_collected/all.0aecd87e873a.js:5417
#: static_collected/all.0db607331718.js:5225
#: static_collected/all.0db607331718.js:5323
#: static_collected/all.146abee8fe99.js:5249
#: static_collected/all.146abee8fe99.js:5347
#: static_collected/all.24315fee0c8e.js:5248
#: static_collected/all.24315fee0c8e.js:5346
#: static_collected/all.483236be7507.js:22
#: static_collected/all.73e18dd7e023.js:5225
#: static_collected/all.73e18dd7e023.js:5323
#: static_collected/all.a650c949d06f.js:5248
#: static_collected/all.a650c949d06f.js:5346
#: static_collected/all.b66e942cdb56.js:5248
#: static_collected/all.b66e942cdb56.js:5346
#: static_collected/all.f62aa30bd0a4.js:5249
#: static_collected/all.f62aa30bd0a4.js:5347 static_collected/all.js:5225
#: static_collected/all.js.c:5323
#: static_collected/admin/js/admin/DateTimeShortcuts.5d58f199725a.js:95
#: static_collected/admin/js/admin/DateTimeShortcuts.5d58f199725a.js:208
#: static_collected/admin/js/admin/DateTimeShortcuts.js:95
#: static_collected/admin/js/admin/DateTimeShortcuts.js:208
#: static_collected/js/host.js:20 static_collected/js/switch-port.js:14
#: static_collected/js/host.e1b01efa0e67.js:20 static_collected/js/host.js:20
#: static_collected/js/switch-port.5eafbc56ee38.js:14
#: static_collected/js/switch-port.js:14
msgid "Cancel"
msgstr "Mégsem"
#: network/static/js/host.js:25 network/static/js/switch-port.js:19
#: static_collected/all.047675ebf594.js:5254
#: static_collected/all.047675ebf594.js:5352
#: static_collected/all.0aecd87e873a.js:5324
#: static_collected/all.0aecd87e873a.js:5422
#: static_collected/all.0db607331718.js:5230
#: static_collected/all.0db607331718.js:5328
#: static_collected/all.146abee8fe99.js:5254
#: static_collected/all.146abee8fe99.js:5352
#: static_collected/all.24315fee0c8e.js:5253
#: static_collected/all.24315fee0c8e.js:5351
#: static_collected/all.483236be7507.js:22
#: static_collected/all.73e18dd7e023.js:5230
#: static_collected/all.73e18dd7e023.js:5328
#: static_collected/all.a650c949d06f.js:5253
#: static_collected/all.a650c949d06f.js:5351
#: static_collected/all.b66e942cdb56.js:5253
#: static_collected/all.b66e942cdb56.js:5351
#: static_collected/all.f62aa30bd0a4.js:5254
#: static_collected/all.f62aa30bd0a4.js:5352 static_collected/all.js:5230
#: static_collected/all.js.c:5328
#: static_collected/admin/js/SelectFilter2.9825381ac407.js:69
#: static_collected/admin/js/SelectFilter2.js:69
#: static_collected/js/host.js:25 static_collected/js/switch-port.js:19
#: static_collected/js/host.e1b01efa0e67.js:25 static_collected/js/host.js:25
#: static_collected/js/switch-port.5eafbc56ee38.js:19
#: static_collected/js/switch-port.js:19
msgid "Remove"
msgstr "Eltávolítás"
#: network/static/js/switch-port.js:8 static_collected/js/switch-port.js:8
#: network/static/js/switch-port.js:8
#: static_collected/all.047675ebf594.js:5341
#: static_collected/all.0aecd87e873a.js:5411
#: static_collected/all.0db607331718.js:5317
#: static_collected/all.146abee8fe99.js:5341
#: static_collected/all.24315fee0c8e.js:5340
#: static_collected/all.483236be7507.js:22
#: static_collected/all.73e18dd7e023.js:5317
#: static_collected/all.a650c949d06f.js:5340
#: static_collected/all.b66e942cdb56.js:5340
#: static_collected/all.f62aa30bd0a4.js:5341 static_collected/all.js:5317
#: static_collected/js/switch-port.5eafbc56ee38.js:8
#: static_collected/js/switch-port.js:8
msgid "Are you sure you want to delete this device?"
msgstr "Biztosan törli ezt az eszközt?"
#: static_collected/vm-detail.e81fe84bf4c0.js:9
msgid ""
"During the tour please don't try the functions because it may lead to "
"graphical glitches, however you can end the tour any time you want with the "
"End Tour button!"
msgstr ""
"A túra során még ne próbálja ki a bemutatott funkciókat, mivel ez "
"megjelenítési problémákat okozhatnak. A túrát bármikor befejezheti a "
"Befejezés gombra kattintva."
#: static_collected/admin/js/SelectFilter2.9825381ac407.js:45
#: static_collected/admin/js/SelectFilter2.js:45
#, c-format
msgid "Available %s"
msgstr "Elérhető %s"
#: static_collected/admin/js/SelectFilter2.9825381ac407.js:46
#: static_collected/admin/js/SelectFilter2.js:46
#, c-format
msgid ""
......@@ -285,33 +860,40 @@ msgstr ""
"Ez az elérhető %s listája. Úgy választhat közülük, hogy rákattint az alábbi "
"dobozban, és megnyomja a dobozok közti \"Választás\" nyilat."
#: static_collected/admin/js/SelectFilter2.9825381ac407.js:53
#: static_collected/admin/js/SelectFilter2.js:53
#, c-format
msgid "Type into this box to filter down the list of available %s."
msgstr "Írjon a mezőbe az elérhető %s szűréséhez."
#: static_collected/admin/js/SelectFilter2.9825381ac407.js:57
#: static_collected/admin/js/SelectFilter2.js:57
msgid "Filter"
msgstr "Szűrő"
#: static_collected/admin/js/SelectFilter2.9825381ac407.js:61
#: static_collected/admin/js/SelectFilter2.js:61
msgid "Choose all"
msgstr "Mindet kijelölni"
#: static_collected/admin/js/SelectFilter2.9825381ac407.js:61
#: static_collected/admin/js/SelectFilter2.js:61
#, c-format
msgid "Click to choose all %s at once."
msgstr "Kattintson az összes %s kiválasztásához."
#: static_collected/admin/js/SelectFilter2.9825381ac407.js:67
#: static_collected/admin/js/SelectFilter2.js:67
msgid "Choose"
msgstr "Választás"
#: static_collected/admin/js/SelectFilter2.9825381ac407.js:75
#: static_collected/admin/js/SelectFilter2.js:75
#, c-format
msgid "Chosen %s"
msgstr "%s kiválasztva"
#: static_collected/admin/js/SelectFilter2.9825381ac407.js:76
#: static_collected/admin/js/SelectFilter2.js:76
#, c-format
msgid ""
......@@ -321,23 +903,29 @@ msgstr ""
"Ez a kiválasztott %s listája. Eltávolíthat közülük, ha rákattint, majd a két "
"doboz közti \"Eltávolítás\" nyílra kattint."
#: static_collected/admin/js/SelectFilter2.9825381ac407.js:80
#: static_collected/admin/js/SelectFilter2.js:80
msgid "Remove all"
msgstr "Összes törlése"
#: static_collected/admin/js/SelectFilter2.9825381ac407.js:80
#: static_collected/admin/js/SelectFilter2.js:80
#, c-format
msgid "Click to remove all chosen %s at once."
msgstr "Kattintson az összes %s eltávolításához."
#: static_collected/admin/js/actions.fd884781224d.js:18
#: static_collected/admin/js/actions.js:18
#: static_collected/admin/js/actions.min.6a5121336635.js:1
#: static_collected/admin/js/actions.min.js:1
msgid "%(sel)s of %(cnt)s selected"
msgid_plural "%(sel)s of %(cnt)s selected"
msgstr[0] "%(sel)s/%(cnt)s kijelölve"
msgstr[1] "%(sel)s/%(cnt)s kijelölve"
#: static_collected/admin/js/actions.fd884781224d.js:109
#: static_collected/admin/js/actions.js:109
#: static_collected/admin/js/actions.min.6a5121336635.js:5
#: static_collected/admin/js/actions.min.js:5
msgid ""
"You have unsaved changes on individual editable fields. If you run an "
......@@ -346,7 +934,9 @@ msgstr ""
"Még el nem mentett módosításai vannak egyes szerkeszthető mezőkön. Ha most "
"futtat egy műveletet, akkor a módosítások elvesznek. "
#: static_collected/admin/js/actions.fd884781224d.js:121
#: static_collected/admin/js/actions.js:121
#: static_collected/admin/js/actions.min.6a5121336635.js:5
#: static_collected/admin/js/actions.min.js:5
msgid ""
"You have selected an action, but you haven't saved your changes to "
......@@ -357,7 +947,9 @@ msgstr ""
"módosításait. Kattintson az OK gombra a mentéshez. Újra kell futtatnia az "
"műveletet."
#: static_collected/admin/js/actions.fd884781224d.js:123
#: static_collected/admin/js/actions.js:123
#: static_collected/admin/js/actions.min.6a5121336635.js:6
#: static_collected/admin/js/actions.min.js:6
msgid ""
"You have selected an action, and you haven't made any changes on individual "
......@@ -367,6 +959,7 @@ msgstr ""
"Kiválasztott egy műveletet, és nem módosított egyetlen mezőt sem. "
"Feltehetően a Mehet gombot keresi a Mentés helyett."
#: static_collected/admin/js/calendar.23d4bc1c37cd.js:8
#: static_collected/admin/js/calendar.js:8
msgid ""
"January February March April May June July August September October November "
......@@ -375,59 +968,80 @@ msgstr ""
"január február március április május június július augusztus szeptember "
"október november december"
#: static_collected/admin/js/calendar.23d4bc1c37cd.js:9
#: static_collected/admin/js/calendar.js:9
msgid "S M T W T F S"
msgstr "V H K Sz Cs P Szo"
#: static_collected/admin/js/collapse.c781bafaf192.js:8
#: static_collected/admin/js/collapse.c781bafaf192.js:19
#: static_collected/admin/js/collapse.js:8
#: static_collected/admin/js/collapse.js:19
#: static_collected/admin/js/collapse.min.ce55331a033c.js:1
#: static_collected/admin/js/collapse.min.js:1
msgid "Show"
msgstr "Mutat"
#: static_collected/admin/js/collapse.c781bafaf192.js:16
#: static_collected/admin/js/collapse.js:16
#: static_collected/admin/js/collapse.min.ce55331a033c.js:1
#: static_collected/admin/js/collapse.min.js:1
msgid "Hide"
msgstr "Elrejt"
#: static_collected/admin/js/admin/DateTimeShortcuts.5d58f199725a.js:52
#: static_collected/admin/js/admin/DateTimeShortcuts.5d58f199725a.js:88
#: static_collected/admin/js/admin/DateTimeShortcuts.js:52
#: static_collected/admin/js/admin/DateTimeShortcuts.js:88
msgid "Now"
msgstr "Most"
#: static_collected/admin/js/admin/DateTimeShortcuts.5d58f199725a.js:56
#: static_collected/admin/js/admin/DateTimeShortcuts.js:56
msgid "Clock"
msgstr "Óra"
#: static_collected/admin/js/admin/DateTimeShortcuts.5d58f199725a.js:84
#: static_collected/admin/js/admin/DateTimeShortcuts.js:84
msgid "Choose a time"
msgstr "Válassza ki az időt"
#: static_collected/admin/js/admin/DateTimeShortcuts.5d58f199725a.js:89
#: static_collected/admin/js/admin/DateTimeShortcuts.js:89
msgid "Midnight"
msgstr "Éjfél"
#: static_collected/admin/js/admin/DateTimeShortcuts.5d58f199725a.js:90
#: static_collected/admin/js/admin/DateTimeShortcuts.js:90
msgid "6 a.m."
msgstr "Reggel 6 óra"
#: static_collected/admin/js/admin/DateTimeShortcuts.5d58f199725a.js:91
#: static_collected/admin/js/admin/DateTimeShortcuts.js:91
msgid "Noon"
msgstr "Dél"
#: static_collected/admin/js/admin/DateTimeShortcuts.5d58f199725a.js:148
#: static_collected/admin/js/admin/DateTimeShortcuts.5d58f199725a.js:201
#: static_collected/admin/js/admin/DateTimeShortcuts.js:148
#: static_collected/admin/js/admin/DateTimeShortcuts.js:201
msgid "Today"
msgstr "Ma"
#: static_collected/admin/js/admin/DateTimeShortcuts.5d58f199725a.js:152
#: static_collected/admin/js/admin/DateTimeShortcuts.js:152
msgid "Calendar"
msgstr "Naptár"
#: static_collected/admin/js/admin/DateTimeShortcuts.5d58f199725a.js:199
#: static_collected/admin/js/admin/DateTimeShortcuts.js:199
msgid "Yesterday"
msgstr "Tegnap"
#: static_collected/admin/js/admin/DateTimeShortcuts.5d58f199725a.js:203
#: static_collected/admin/js/admin/DateTimeShortcuts.js:203
msgid "Tomorrow"
msgstr "Holnap"
#~ msgid "Prevent newline at end of file"
#~ msgstr "x"
......@@ -18,26 +18,37 @@
from logging import getLogger
from django.db.models import Sum
from django.utils.translation import ugettext_noop
from common.models import HumanReadableException
logger = getLogger(__name__)
class NotEnoughMemoryException(Exception):
class SchedulerError(HumanReadableException):
admin_message = None
def __init__(self, message=None):
if message is None:
message = "No node has enough memory to accomodate the guest."
def __init__(self, params=None, level=None, **kwargs):
kwargs.update(params or {})
super(SchedulerError, self).__init__(
level, self.message, self.admin_message or self.message,
kwargs)
Exception.__init__(self, message)
class NotEnoughMemoryException(SchedulerError):
message = ugettext_noop(
"The resources required for launching the virtual machine are not "
"available currently. Please try again later.")
class TraitsUnsatisfiableException(Exception):
admin_message = ugettext_noop(
"The required free memory for launching the virtual machine is not "
"available on any usable node currently. Please try again later.")
def __init__(self, message=None):
if message is None:
message = "No node can satisfy all required traits of the guest."
Exception.__init__(self, message)
class TraitsUnsatisfiableException(SchedulerError):
message = ugettext_noop(
"No node can satisfy the required traits of the "
"new vitual machine currently.")
def select_node(instance, nodes):
......@@ -77,18 +88,26 @@ def has_enough_ram(ram_size, node):
"""True, if the node has enough memory to accomodate a guest requiring
ram_size mebibytes of memory; otherwise, false.
"""
ram_size = ram_size * 1024 * 1024
try:
total = node.ram_size
used = (node.ram_usage / 100) * total
used = node.byte_ram_usage
unused = total - used
overcommit = node.ram_size_with_overcommit
reserved = node.instance_set.aggregate(r=Sum('ram_size'))['r'] or 0
reserved = (node.instance_set.aggregate(
r=Sum('ram_size'))['r'] or 0) * 1024 * 1024
free = overcommit - reserved
return ram_size < unused and ram_size < free
retval = ram_size < unused and ram_size < free
logger.debug('has_enough_ram(%d, %s)=%s (total=%s unused=%s'
' overcommit=%s free=%s free_ok=%s overcommit_ok=%s)',
ram_size, node, retval, total, unused, overcommit, free,
ram_size < unused, ram_size < free)
return retval
except TypeError as e:
logger.warning('Got incorrect monitoring data for node %s. %s',
logger.exception('Got incorrect monitoring data for node %s. %s',
unicode(node), unicode(e))
return False
......
......@@ -17,6 +17,7 @@
from django.forms import ModelForm
from django.core.urlresolvers import reverse_lazy
from django.utils.translation import ugettext_lazy as _
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Fieldset, Div, Submit, BaseInput
......@@ -56,8 +57,9 @@ class BlacklistItemForm(ModelForm):
)
),
FormActions(
Submit('submit', 'Save changes'),
LinkButton('back', 'Back', reverse_lazy('network.blacklist_list'))
Submit('submit', _('Save changes')),
LinkButton('back', _("Back"),
reverse_lazy('network.blacklist_list'))
)
)
......@@ -77,8 +79,8 @@ class DomainForm(ModelForm):
),
),
FormActions(
Submit('submit', 'Save'),
LinkButton('back', 'Back', reverse_lazy('network.domain_list'))
Submit('submit', _('Save')),
LinkButton('back', _("Back"), reverse_lazy('network.domain_list'))
)
)
......@@ -91,15 +93,15 @@ class GroupForm(ModelForm):
helper.layout = Layout(
Div(
Fieldset(
'Identity',
'',
'name',
'description',
'owner',
),
),
FormActions(
Submit('submit', 'Save'),
LinkButton('back', 'Back', reverse_lazy('network.group_list'))
Submit('submit', _('Save')),
LinkButton('back', _("Back"), reverse_lazy('network.group_list'))
)
)
......@@ -112,13 +114,13 @@ class HostForm(ModelForm):
helper.layout = Layout(
Div(
Fieldset(
'Identity',
'',
'hostname',
'reverse',
'mac',
),
Fieldset(
'Network',
_('Network'),
'vlan',
'ipv4',
'ipv6',
......@@ -126,7 +128,7 @@ class HostForm(ModelForm):
'external_ipv4',
),
Fieldset(
'Information',
_('Information'),
'description',
'location',
'comment',
......@@ -134,8 +136,8 @@ class HostForm(ModelForm):
),
),
FormActions(
Submit('submit', 'Save'),
LinkButton('back', 'Back', reverse_lazy('network.host_list')))
Submit('submit', _('Save')),
LinkButton('back', _('Back'), reverse_lazy('network.host_list')))
)
class Meta:
......@@ -159,8 +161,8 @@ class RecordForm(ModelForm):
)
),
FormActions(
Submit('submit', 'Save'),
LinkButton('back', 'Back', reverse_lazy('network.record_list'))
Submit('submit', _("Save")),
LinkButton('back', _("Back"), reverse_lazy('network.record_list'))
)
)
......@@ -173,7 +175,7 @@ class RuleForm(ModelForm):
helper.layout = Layout(
Div(
Fieldset(
'Identity',
'',
'direction',
'description',
'foreign_network',
......@@ -189,7 +191,7 @@ class RuleForm(ModelForm):
'nat_external_ipv4',
),
Fieldset(
'External',
_('External'),
'vlan',
'vlangroup',
'host',
......@@ -198,8 +200,8 @@ class RuleForm(ModelForm):
)
),
FormActions(
Submit('submit', 'Save'),
LinkButton('back', 'Back', reverse_lazy('network.rule_list'))
Submit('submit', _("Save")),
LinkButton('back', _("Back"), reverse_lazy('network.rule_list'))
)
)
......@@ -219,8 +221,8 @@ class SwitchPortForm(ModelForm):
)
),
FormActions(
Submit('submit', 'Save'),
LinkButton('back', 'Back',
Submit('submit', _("Save")),
LinkButton('back', _("Back"),
reverse_lazy('network.switch_port_list'))
)
)
......@@ -234,41 +236,42 @@ class VlanForm(ModelForm):
helper.layout = Layout(
Div(
Fieldset(
'Identity',
'',
'name',
'vid',
'network_type',
'managed',
),
Fieldset(
'IPv4',
_('IPv4'),
'network4',
'snat_to',
'snat_ip',
'dhcp_pool',
),
Fieldset(
'IPv6',
_('IPv6'),
'network6',
'ipv6_template',
'host_ipv6_prefixlen',
),
Fieldset(
'Domain name service',
_('Domain name service'),
'domain',
'reverse_domain',
),
Fieldset(
'Info',
_('Info'),
'description',
'comment',
'owner',
# 'created_at',
# 'modified_at',
),
),
FormActions(
Submit('submit', 'Save'),
LinkButton('back', 'Back', reverse_lazy('network.vlan_list'))
Submit('submit', _("Save")),
LinkButton('back', _("Back"), reverse_lazy('network.vlan_list'))
)
)
......@@ -289,8 +292,8 @@ class VlanGroupForm(ModelForm):
)
),
FormActions(
Submit('submit', 'Save'),
LinkButton('back', 'Back', reverse_lazy(
Submit('submit', _("Save")),
LinkButton('back', _("Back"), reverse_lazy(
'network.vlan_group_list'))
)
)
......
......@@ -6,3 +6,8 @@
text-align: center;
}
#host-detail-records-table td:first-child,
#host-detail-records-table th:first-child {
text-align: center;
width: 60px;
}
......@@ -15,6 +15,8 @@
# You should have received a copy of the GNU General Public License along
# with CIRCLE. If not, see <http://www.gnu.org/licenses/>.
from django.utils.translation import ugettext_lazy as _
from django_tables2 import Table, A
from django_tables2.columns import LinkColumn, TemplateColumn
......@@ -181,3 +183,20 @@ class VlanGroupTable(Table):
attrs = {'class': 'table table-striped table-condensed'}
fields = ('name', 'vlans', 'description', 'owner', )
order_by = 'name'
class HostRecordsTable(Table):
fqdn = LinkColumn(
"network.record", args=[A("pk")],
order_by=("name", ),
)
class Meta:
model = Record
attrs = {
'class': "table table-striped table-bordered",
'id': "host-detail-records-table",
}
fields = ("type", "fqdn")
order_by = ("name", )
empty_text = _("No records.")
{% load i18n %}
{% load l10n %}
{# <span style="color: #FF0000;">[{{ record.r_type }}]</span> #}
{% if record.direction == "1" %}
{% if record.direction == "in" %}
{{ record.foreign_network }}
[{% for v in record.foreign_network.vlans.all %}
{{ v.name }}{% if not forloop.last %},{% endif %}
{% endfor %}]
{% else %}
{% if record.r_type == "host" %}
{{ record.host.get_fqdn }}
......@@ -11,10 +13,10 @@
{{ record.r_type }}
{% endif %}
{% endif %}
{#<span style="color: #0000FF;"> ▸ </span>#}
<i class="fa fa-arrow-right"></i>
{% if record.direction == "0" %}
{% if record.direction == "out" %}
{{ record.foreign_network }}
{% else %}
{% if record.r_type == "host" %}
......@@ -33,6 +35,11 @@
{% if record.nat %}
<span class="label label-success">NAT
[ {{ record.dport }} <i class="fa fa-arrow-right"></i>
{{record.nat_external_port}} ]</span>
[
{{record.nat_external_port}}
<i class="fa fa-arrow-right"></i>
{{ record.dport }}
]
{{ record.proto|upper }}
</span>
{% endif %}
......@@ -12,10 +12,10 @@
</div>
<div class="row">
<div class="col-sm-7">
<div class="col-md-6">
{% crispy form %}
</div>
<div class="col-sm-5">
<div class="col-md-6">
<div class="page-header">
<a href="{% url "network.rule_create" %}?host={{ host_pk }}" class="btn btn-success pull-right btn-xs"><i class="fa fa-plus-circle"></i> {% trans "Add new rule" %}</a>
<h3>{% trans "Rules" %}</h3>
......@@ -23,7 +23,7 @@
{% if rule_list.data.data.count > 0 %}
{% render_table rule_list %}
{% else %}
{% trans "No rules associated with this host!" %}
{% trans "No rules associated with this host." %}
{% endif %}
<div class="page-header">
......@@ -45,10 +45,10 @@
{% endif %}
<div class="page-header">
<h3>Add host group</h3>
<h3>{% trans "Add host group" %}</h3>
</div>
{% if not_used_groups|length == 0 %}
No more groups to add!
{% trans "No more groups to add" %}
{% else %}
<form action="{% url "network.add_host_group" pk=host_pk %}" method="POST">
{% csrf_token %}
......@@ -64,11 +64,20 @@
</div><!-- input-group -->
</form>
{% endif %}
</div><!-- col-sm-4 -->
<div class="page-header">
<a href="{% url "network.record_create" %}?host={{ host_pk }}"
class="btn btn-xs btn-success pull-right">
<i class="fa fa-plus-circle"></i>
{% trans "Add new CNAME record" %}
</a>
<h3>{% trans "Records" %}</h3>
</div>
{% render_table records_table %}
</div><!-- col-sm-5 -->
</div><!-- row -->
{% endblock %}
{% block extra_etc %}
<script src="{% static "js/host.js" %}"></script>
<script src="{% static "js/host.js" %}"></script>
{% endblock %}
......@@ -34,6 +34,7 @@ from .forms import (HostForm, VlanForm, DomainForm, GroupForm, RecordForm,
BlacklistItemForm, RuleForm, VlanGroupForm, SwitchPortForm)
from django.contrib import messages
from django.contrib.messages.views import SuccessMessageMixin
from django.views.generic.edit import FormMixin
from django.utils.translation import ugettext_lazy as _
from braces.views import LoginRequiredMixin, SuperuserRequiredMixin
......@@ -42,25 +43,14 @@ from operator import itemgetter
from itertools import chain
import json
from dashboard.views import AclUpdateView
from dashboard.forms import AclUserAddForm
from dashboard.forms import AclUserOrGroupAddForm
class SuccessMessageMixin(FormMixin):
"""
Adds a success message on successful form submission.
From django/contrib/messages/views.py@9a85ad89
"""
success_message = ''
def form_valid(self, form):
response = super(SuccessMessageMixin, self).form_valid(form)
success_message = self.get_success_message(form.cleaned_data)
if success_message:
messages.success(self.request, success_message)
return response
def get_success_message(self, cleaned_data):
return self.success_message % cleaned_data
class InitialOwnerMixin(FormMixin):
def get_initial(self):
initial = super(InitialOwnerMixin, self).get_initial()
initial['owner'] = self.request.user
return initial
class IndexView(LoginRequiredMixin, SuperuserRequiredMixin, TemplateView):
......@@ -190,7 +180,7 @@ class DomainDetail(LoginRequiredMixin, SuperuserRequiredMixin,
class DomainCreate(LoginRequiredMixin, SuperuserRequiredMixin,
SuccessMessageMixin, CreateView):
SuccessMessageMixin, InitialOwnerMixin, CreateView):
model = Domain
template_name = "network/domain-create.html"
form_class = DomainForm
......@@ -274,7 +264,7 @@ class GroupList(LoginRequiredMixin, SuperuserRequiredMixin, SingleTableView):
class GroupCreate(LoginRequiredMixin, SuperuserRequiredMixin,
SuccessMessageMixin, CreateView):
SuccessMessageMixin, InitialOwnerMixin, CreateView):
model = Group
template_name = "network/group-create.html"
form_class = GroupForm
......@@ -399,6 +389,12 @@ class HostDetail(LoginRequiredMixin, SuperuserRequiredMixin,
# set host pk (we need this for URL-s)
context['host_pk'] = self.kwargs['pk']
from network.tables import HostRecordsTable
context['records_table'] = HostRecordsTable(
Record.objects.filter(host=self.get_object()),
request=self.request, template="django_tables2/table_no_page.html"
)
return context
def get_success_url(self):
......@@ -407,7 +403,7 @@ class HostDetail(LoginRequiredMixin, SuperuserRequiredMixin,
class HostCreate(LoginRequiredMixin, SuperuserRequiredMixin,
SuccessMessageMixin, CreateView):
SuccessMessageMixin, InitialOwnerMixin, CreateView):
model = Host
template_name = "network/host-create.html"
form_class = HostForm
......@@ -491,7 +487,7 @@ class RecordDetail(LoginRequiredMixin, SuperuserRequiredMixin,
class RecordCreate(LoginRequiredMixin, SuperuserRequiredMixin,
SuccessMessageMixin, CreateView):
SuccessMessageMixin, InitialOwnerMixin, CreateView):
model = Record
template_name = "network/record-create.html"
form_class = RecordForm
......@@ -499,10 +495,23 @@ class RecordCreate(LoginRequiredMixin, SuperuserRequiredMixin,
success_message = _(u'Successfully created record!')
def get_initial(self):
return {
# 'owner': 1,
'domain': self.request.GET.get('domain'),
}
initial = super(RecordCreate, self).get_initial()
initial['domain'] = self.request.GET.get('domain')
host_pk = self.request.GET.get("host")
try:
host = Host.objects.get(pk=host_pk)
except (Host.DoesNotExist, ValueError):
host = None
if host:
initial.update({
'type': "CNAME",
'host': host,
'address': host.get_fqdn(),
})
return initial
class RecordDelete(LoginRequiredMixin, SuperuserRequiredMixin, DeleteView):
......@@ -550,18 +559,19 @@ class RuleDetail(LoginRequiredMixin, SuperuserRequiredMixin,
class RuleCreate(LoginRequiredMixin, SuperuserRequiredMixin,
SuccessMessageMixin, CreateView):
SuccessMessageMixin, InitialOwnerMixin, CreateView):
model = Rule
template_name = "network/rule-create.html"
form_class = RuleForm
success_message = _(u'Successfully created rule!')
def get_initial(self):
return {
# 'owner': 1,
initial = super(RuleCreate, self).get_initial()
initial.update({
'host': self.request.GET.get('host'),
'hostgroup': self.request.GET.get('hostgroup')
}
})
return initial
class RuleDelete(LoginRequiredMixin, SuperuserRequiredMixin, DeleteView):
......@@ -654,14 +664,14 @@ class VlanDetail(LoginRequiredMixin, SuperuserRequiredMixin,
context['vlan_vid'] = self.kwargs.get('vid')
context['acl'] = AclUpdateView.get_acl_data(
self.object, self.request.user, 'network.vlan-acl')
context['aclform'] = AclUserAddForm()
context['aclform'] = AclUserOrGroupAddForm()
return context
success_url = reverse_lazy('network.vlan_list')
class VlanCreate(LoginRequiredMixin, SuperuserRequiredMixin,
SuccessMessageMixin, CreateView):
SuccessMessageMixin, InitialOwnerMixin, CreateView):
model = Vlan
template_name = "network/vlan-create.html"
form_class = VlanForm
......@@ -741,7 +751,7 @@ class VlanGroupDetail(LoginRequiredMixin, SuperuserRequiredMixin,
class VlanGroupCreate(LoginRequiredMixin, SuperuserRequiredMixin,
SuccessMessageMixin, CreateView):
SuccessMessageMixin, InitialOwnerMixin, CreateView):
model = VlanGroup
template_name = "network/vlan-group-create.html"
form_class = VlanGroupForm
......
......@@ -278,7 +278,7 @@ class Disk(TimeStampedModel):
return Disk.create(base=self, datastore=self.datastore,
name=self.name, size=self.size,
type=new_type)
type=new_type, dev_num=self.dev_num)
def get_vmdisk_desc(self):
"""Serialize disk object to the vmdriver.
......@@ -367,7 +367,8 @@ class Disk(TimeStampedModel):
disk = cls.__create(user, params)
disk.clean()
disk.save()
logger.debug("Disk created: %s", params)
logger.debug(u"Disk created from: %s",
unicode(params.get("base", "nobase")))
return disk
@classmethod
......
......@@ -11,10 +11,6 @@
body {
margin-top: 40px;
}
.container {
width: 600px;
}
ul, li {
list-style: none;
margin: 0;
......@@ -22,6 +18,8 @@
}
.container > .content {
max-width: 570px;
margin: auto;
background-color: #fff;
padding: 20px;
-webkit-border-radius: 10px 10px 10px 10px;
......@@ -38,8 +36,10 @@
}
.login-form {
margin-top: 40px;
margin: 20px auto 0 auto;
padding: 0 10px;
max-width: 250px;
}
.login-form form {
......@@ -79,3 +79,10 @@
<img src="{% static "dashboard/img/logo.png" %}" style="height: 25px;"/>
</a>
{% endblock %}
{% block content %}
<div class="content">
{% block content_box %}{% endblock %}
</div>
{% endblock %}
......@@ -12,15 +12,14 @@
</a>
{% endblock %}
{% block content %}
<div class="content">
{% block content_box %}
<div class="row">
{% if form.password.errors or form.username.errors %}
<div class="login-form-errors">
{% include "display-form-errors.html" %}
</div>
{% endif %}
<div class="col-sm-{% if saml2 %}6{% else %}12{% endif %}">
<div class="col-xs-{% if saml2 %}6{% else %}12{% endif %}">
<div class="login-form">
<form action="" method="POST">
{% csrf_token %}
......@@ -29,8 +28,8 @@
</div>
</div>
{% if saml2 %}
<div class="col-sm-6">
<h4 style="padding-top: 0; margin-top: 0;">{% trans "Login with SSO" %}</h4>
<div class="col-xs-6">
<h4 style="padding-top: 0; margin-top: 20px;">{% trans "Login with SSO" %}</h4>
<a href="{% url "saml2_login" %}">{% trans "Click here!" %}</a>
</div>
{% endif %}
......
......@@ -5,9 +5,8 @@
{% block title-page %}{% trans "Password reset complete" %}{% endblock %}
{% block content %}
<div class="content">
<div class="row">
{% block content_box %}
<div class="row">
<div class="login-form-errors">
{% include "display-form-errors.html" %}
</div>
......@@ -17,6 +16,5 @@
<a href="{% url "accounts.login" %}">{% trans "Click here to login" %}</a>
</div>
</div>
</div>
</div>
{% endblock %}
......@@ -5,15 +5,16 @@
{% block title-page %}{% trans "Password reset confirm" %}{% endblock %}
{% block content %}
<div>
<div class="row">
{% block content_box %}
<div class="row">
<div class="login-form-errors">
{% include "display-form-errors.html" %}
</div>
<div class="col-sm-12">
<div style="margin: 0 0 25px 0;">
{% blocktrans %}Please enter your new password twice so we can verify you typed it in correctly!{% endblocktrans %}
<div>
{% blocktrans %}
Please enter your new password twice so we can verify you typed it in correctly.
{% endblocktrans %}
</div>
{% if form %}
......@@ -21,10 +22,9 @@
{% else %}
<div class="alert alert-warning">
{% url "accounts.password-reset" as url %}
{% blocktrans with url=url %}This token is expired, please <a href="{{ url }}">request</a> a new password reset link again!{% endblocktrans %}
{% blocktrans with url=url %}This token is expired, please <a href="{{ url }}">request</a> a new password reset link again.{% endblocktrans %}
</div>
{% endif %}
</div>
</div>
</div>
{% endblock %}
......@@ -5,16 +5,14 @@
{% block title-page %}{% trans "Password reset done" %}{% endblock %}
{% block content %}
<div class="content">
<div class="row">
{% block content_box %}
<div class="row">
<div class="login-form-errors">
{% include "display-form-errors.html" %}
</div>
<div class="col-sm-12">
<div class="pull-right"><a href="{% url "accounts.login" %}">{% trans "Back to login" %}</a></div>
{% trans "We have sent you an email about your next steps!" %}
</div>
{% trans "We have sent you an email about your next steps." %}
</div>
</div>
{% endblock %}
......@@ -5,20 +5,20 @@
{% block title-page %}{% trans "Password reset" %}{% endblock %}
{% block content %}
<div class="content">
<div class="row">
{% block content_box %}
<div class="row">
<div class="login-form-errors">
{% include "display-form-errors.html" %}
</div>
<div class="col-sm-12">
<div class="pull-right"><a href="{% url "accounts.login" %}">{% trans "Back to login" %}</a></div>
<h4 style="margin: 0 0 25px 0;">{% blocktrans %}Enter your email address to reset your password!{% endblocktrans %}</h4>
<h4 style="margin: 0 0 25px 0;">
{% blocktrans %}Enter your email address to reset your password.{% endblocktrans %}
</h4>
<form action="" method="POST">
{% csrf_token %}
{% crispy form %}
</form>
</div>
</div>
</div>
{% endblock %}
# -*- 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):
# Deleting field 'Instance.active_since'
db.delete_column(u'vm_instance', 'active_since')
def backwards(self, orm):
# Adding field 'Instance.active_since'
db.add_column(u'vm_instance', 'active_since',
self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True),
keep_default=False)
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.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.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.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'storage.datastore': {
'Meta': {'ordering': "[u'name']", 'object_name': 'DataStore'},
'hostname': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200'})
},
u'storage.disk': {
'Meta': {'ordering': "[u'name']", 'object_name': 'Disk'},
'base': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'derivatives'", 'null': 'True', 'to': u"orm['storage.Disk']"}),
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
'datastore': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['storage.DataStore']"}),
'destroyed': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
'dev_num': ('django.db.models.fields.CharField', [], {'default': "u'a'", 'max_length': '1'}),
'filename': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '256'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_ready': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'size': ('sizefield.models.FileSizeField', [], {'default': 'None', 'null': 'True'}),
'type': ('django.db.models.fields.CharField', [], {'max_length': '10'})
},
u'vm.instance': {
'Meta': {'ordering': "(u'pk',)", 'object_name': 'Instance'},
'access_method': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
'arch': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
'boot_menu': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'destroyed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'disks': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "u'instance_set'", 'symmetrical': 'False', 'to': u"orm['storage.Disk']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_base': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'lease': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['vm.Lease']"}),
'max_ram_size': ('django.db.models.fields.IntegerField', [], {}),
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'node': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'instance_set'", 'null': 'True', 'to': u"orm['vm.Node']"}),
'num_cores': ('django.db.models.fields.IntegerField', [], {}),
'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
'priority': ('django.db.models.fields.IntegerField', [], {}),
'pw': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
'ram_size': ('django.db.models.fields.IntegerField', [], {}),
'raw_data': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'req_traits': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['vm.Trait']", 'symmetrical': 'False', 'blank': 'True'}),
'status': ('model_utils.fields.StatusField', [], {'default': "u'NOSTATE'", 'max_length': '100', u'no_check_for_status': 'True'}),
'status_changed': ('model_utils.fields.MonitorField', [], {'default': 'datetime.datetime.now', u'monitor': "u'status'"}),
'system': ('django.db.models.fields.TextField', [], {}),
'template': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'instance_set'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['vm.InstanceTemplate']"}),
'time_of_delete': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
'time_of_suspend': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
'vnc_port': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'})
},
u'vm.instanceactivity': {
'Meta': {'ordering': "[u'-finished', u'-started', u'instance', u'-id']", 'object_name': 'InstanceActivity'},
'activity_code': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
'finished': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'instance': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'activity_log'", 'to': u"orm['vm.Instance']"}),
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': u"orm['vm.InstanceActivity']"}),
'readable_name_data': ('jsonfield.fields.JSONField', [], {'null': 'True', 'blank': 'True'}),
'result_data': ('jsonfield.fields.JSONField', [], {'null': 'True', 'blank': 'True'}),
'resultant_state': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}),
'started': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'succeeded': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
'task_uuid': ('django.db.models.fields.CharField', [], {'max_length': '50', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'})
},
u'vm.instancetemplate': {
'Meta': {'ordering': "(u'name',)", 'object_name': 'InstanceTemplate'},
'access_method': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
'arch': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
'boot_menu': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'disks': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "u'template_set'", 'symmetrical': 'False', 'to': u"orm['storage.Disk']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'lease': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['vm.Lease']"}),
'max_ram_size': ('django.db.models.fields.IntegerField', [], {}),
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'num_cores': ('django.db.models.fields.IntegerField', [], {}),
'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['vm.InstanceTemplate']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}),
'priority': ('django.db.models.fields.IntegerField', [], {}),
'ram_size': ('django.db.models.fields.IntegerField', [], {}),
'raw_data': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'req_traits': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['vm.Trait']", 'symmetrical': 'False', 'blank': 'True'}),
'system': ('django.db.models.fields.TextField', [], {})
},
u'vm.interface': {
'Meta': {'ordering': "(u'-vlan__managed',)", 'object_name': 'Interface'},
'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'}),
'instance': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'interface_set'", 'to': u"orm['vm.Instance']"}),
'vlan': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'vm_interface'", 'to': u"orm['firewall.Vlan']"})
},
u'vm.interfacetemplate': {
'Meta': {'object_name': 'InterfaceTemplate'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'managed': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'template': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'interface_set'", 'to': u"orm['vm.InstanceTemplate']"}),
'vlan': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['firewall.Vlan']"})
},
u'vm.lease': {
'Meta': {'ordering': "[u'name']", 'object_name': 'Lease'},
'delete_interval_seconds': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'suspend_interval_seconds': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
},
u'vm.namedbaseresourceconfig': {
'Meta': {'object_name': 'NamedBaseResourceConfig'},
'arch': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'max_ram_size': ('django.db.models.fields.IntegerField', [], {}),
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '50'}),
'num_cores': ('django.db.models.fields.IntegerField', [], {}),
'priority': ('django.db.models.fields.IntegerField', [], {}),
'ram_size': ('django.db.models.fields.IntegerField', [], {})
},
u'vm.node': {
'Meta': {'ordering': "(u'-enabled', u'normalized_name')", 'object_name': 'Node'},
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'host': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['firewall.Host']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '50'}),
'normalized_name': ('common.models.HumanSortField', [], {'default': "''", 'maximum_number_length': '4', 'max_length': '100', 'monitor': "u'name'", 'blank': 'True'}),
'overcommit': ('django.db.models.fields.FloatField', [], {'default': '1.0'}),
'priority': ('django.db.models.fields.IntegerField', [], {}),
'traits': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['vm.Trait']", 'symmetrical': 'False', 'blank': 'True'})
},
u'vm.nodeactivity': {
'Meta': {'object_name': 'NodeActivity'},
'activity_code': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
'finished': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'activity_log'", 'to': u"orm['vm.Node']"}),
'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': u"orm['vm.NodeActivity']"}),
'readable_name_data': ('jsonfield.fields.JSONField', [], {'null': 'True', 'blank': 'True'}),
'result_data': ('jsonfield.fields.JSONField', [], {'null': 'True', 'blank': 'True'}),
'started': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'succeeded': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
'task_uuid': ('django.db.models.fields.CharField', [], {'max_length': '50', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'})
},
u'vm.trait': {
'Meta': {'object_name': 'Trait'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
}
}
complete_apps = ['vm']
\ No newline at end of file
# -*- 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):
# Adding field 'Instance.has_agent'
db.add_column(u'vm_instance', 'has_agent',
self.gf('django.db.models.fields.BooleanField')(default=True),
keep_default=False)
# Adding field 'InstanceTemplate.has_agent'
db.add_column(u'vm_instancetemplate', 'has_agent',
self.gf('django.db.models.fields.BooleanField')(default=True),
keep_default=False)
# Adding field 'InstanceActivity.interruptible'
db.add_column(u'vm_instanceactivity', 'interruptible',
self.gf('django.db.models.fields.BooleanField')(default=False),
keep_default=False)
def backwards(self, orm):
# Deleting field 'Instance.has_agent'
db.delete_column(u'vm_instance', 'has_agent')
# Deleting field 'InstanceTemplate.has_agent'
db.delete_column(u'vm_instancetemplate', 'has_agent')
# Deleting field 'InstanceActivity.interruptible'
db.delete_column(u'vm_instanceactivity', 'interruptible')
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.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.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.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'storage.datastore': {
'Meta': {'ordering': "[u'name']", 'object_name': 'DataStore'},
'hostname': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200'})
},
u'storage.disk': {
'Meta': {'ordering': "[u'name']", 'object_name': 'Disk'},
'base': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'derivatives'", 'null': 'True', 'to': u"orm['storage.Disk']"}),
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
'datastore': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['storage.DataStore']"}),
'destroyed': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
'dev_num': ('django.db.models.fields.CharField', [], {'default': "u'a'", 'max_length': '1'}),
'filename': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '256'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_ready': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'size': ('sizefield.models.FileSizeField', [], {'default': 'None', 'null': 'True'}),
'type': ('django.db.models.fields.CharField', [], {'max_length': '10'})
},
u'vm.instance': {
'Meta': {'ordering': "(u'pk',)", 'object_name': 'Instance'},
'access_method': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
'arch': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
'boot_menu': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'destroyed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'disks': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "u'instance_set'", 'symmetrical': 'False', 'to': u"orm['storage.Disk']"}),
'has_agent': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_base': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'lease': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['vm.Lease']"}),
'max_ram_size': ('django.db.models.fields.IntegerField', [], {}),
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'node': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'instance_set'", 'null': 'True', 'to': u"orm['vm.Node']"}),
'num_cores': ('django.db.models.fields.IntegerField', [], {}),
'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
'priority': ('django.db.models.fields.IntegerField', [], {}),
'pw': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
'ram_size': ('django.db.models.fields.IntegerField', [], {}),
'raw_data': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'req_traits': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['vm.Trait']", 'symmetrical': 'False', 'blank': 'True'}),
'status': ('model_utils.fields.StatusField', [], {'default': "u'NOSTATE'", 'max_length': '100', u'no_check_for_status': 'True'}),
'status_changed': ('model_utils.fields.MonitorField', [], {'default': 'datetime.datetime.now', u'monitor': "u'status'"}),
'system': ('django.db.models.fields.TextField', [], {}),
'template': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'instance_set'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['vm.InstanceTemplate']"}),
'time_of_delete': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
'time_of_suspend': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
'vnc_port': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'})
},
u'vm.instanceactivity': {
'Meta': {'ordering': "[u'-finished', u'-started', u'instance', u'-id']", 'object_name': 'InstanceActivity'},
'activity_code': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
'finished': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'instance': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'activity_log'", 'to': u"orm['vm.Instance']"}),
'interruptible': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': u"orm['vm.InstanceActivity']"}),
'readable_name_data': ('jsonfield.fields.JSONField', [], {'null': 'True', 'blank': 'True'}),
'result_data': ('jsonfield.fields.JSONField', [], {'null': 'True', 'blank': 'True'}),
'resultant_state': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}),
'started': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'succeeded': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
'task_uuid': ('django.db.models.fields.CharField', [], {'max_length': '50', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'})
},
u'vm.instancetemplate': {
'Meta': {'ordering': "(u'name',)", 'object_name': 'InstanceTemplate'},
'access_method': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
'arch': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
'boot_menu': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'disks': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "u'template_set'", 'symmetrical': 'False', 'to': u"orm['storage.Disk']"}),
'has_agent': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'lease': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['vm.Lease']"}),
'max_ram_size': ('django.db.models.fields.IntegerField', [], {}),
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'num_cores': ('django.db.models.fields.IntegerField', [], {}),
'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['vm.InstanceTemplate']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}),
'priority': ('django.db.models.fields.IntegerField', [], {}),
'ram_size': ('django.db.models.fields.IntegerField', [], {}),
'raw_data': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'req_traits': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['vm.Trait']", 'symmetrical': 'False', 'blank': 'True'}),
'system': ('django.db.models.fields.TextField', [], {})
},
u'vm.interface': {
'Meta': {'ordering': "(u'-vlan__managed',)", 'object_name': 'Interface'},
'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'}),
'instance': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'interface_set'", 'to': u"orm['vm.Instance']"}),
'vlan': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'vm_interface'", 'to': u"orm['firewall.Vlan']"})
},
u'vm.interfacetemplate': {
'Meta': {'object_name': 'InterfaceTemplate'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'managed': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'template': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'interface_set'", 'to': u"orm['vm.InstanceTemplate']"}),
'vlan': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['firewall.Vlan']"})
},
u'vm.lease': {
'Meta': {'ordering': "[u'name']", 'object_name': 'Lease'},
'delete_interval_seconds': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'suspend_interval_seconds': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
},
u'vm.namedbaseresourceconfig': {
'Meta': {'object_name': 'NamedBaseResourceConfig'},
'arch': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'max_ram_size': ('django.db.models.fields.IntegerField', [], {}),
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '50'}),
'num_cores': ('django.db.models.fields.IntegerField', [], {}),
'priority': ('django.db.models.fields.IntegerField', [], {}),
'ram_size': ('django.db.models.fields.IntegerField', [], {})
},
u'vm.node': {
'Meta': {'ordering': "(u'-enabled', u'normalized_name')", 'object_name': 'Node'},
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'host': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['firewall.Host']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '50'}),
'normalized_name': ('common.models.HumanSortField', [], {'default': "''", 'maximum_number_length': '4', 'max_length': '100', 'monitor': "u'name'", 'blank': 'True'}),
'overcommit': ('django.db.models.fields.FloatField', [], {'default': '1.0'}),
'priority': ('django.db.models.fields.IntegerField', [], {}),
'traits': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['vm.Trait']", 'symmetrical': 'False', 'blank': 'True'})
},
u'vm.nodeactivity': {
'Meta': {'object_name': 'NodeActivity'},
'activity_code': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
'finished': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'activity_log'", 'to': u"orm['vm.Node']"}),
'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': u"orm['vm.NodeActivity']"}),
'readable_name_data': ('jsonfield.fields.JSONField', [], {'null': 'True', 'blank': 'True'}),
'result_data': ('jsonfield.fields.JSONField', [], {'null': 'True', 'blank': 'True'}),
'started': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'succeeded': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
'task_uuid': ('django.db.models.fields.CharField', [], {'max_length': '50', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'})
},
u'vm.trait': {
'Meta': {'object_name': 'Trait'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
}
}
complete_apps = ['vm']
......@@ -24,7 +24,7 @@ from celery.signals import worker_ready
from celery.contrib.abortable import AbortableAsyncResult
from django.core.urlresolvers import reverse
from django.db.models import CharField, ForeignKey
from django.db.models import CharField, ForeignKey, BooleanField
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _, ugettext_noop
......@@ -70,6 +70,8 @@ class InstanceActivity(ActivityModel):
help_text=_('Instance this activity works on.'),
verbose_name=_('instance'))
resultant_state = CharField(blank=True, max_length=20, null=True)
interruptible = BooleanField(default=False, help_text=_(
'Other activities can interrupt this one.'))
class Meta:
app_label = 'vm'
......@@ -91,24 +93,30 @@ class InstanceActivity(ActivityModel):
@classmethod
def create(cls, code_suffix, instance, task_uuid=None, user=None,
concurrency_check=True, readable_name=None,
resultant_state=None):
resultant_state=None, interruptible=False):
readable_name = _normalize_readable_name(readable_name, code_suffix)
# Check for concurrent activities
active_activities = instance.activity_log.filter(finished__isnull=True)
if concurrency_check and active_activities.exists():
raise ActivityInProgressError.create(active_activities[0])
for i in active_activities:
if i.interruptible:
i.finish(False, result=ugettext_noop(
"Interrupted by other activity."))
else:
raise ActivityInProgressError.create(i)
activity_code = join_activity_code(cls.ACTIVITY_CODE_BASE, code_suffix)
activity_code = cls.construct_activity_code(code_suffix)
act = cls(activity_code=activity_code, instance=instance, parent=None,
resultant_state=resultant_state, started=timezone.now(),
readable_name_data=readable_name.to_dict(),
task_uuid=task_uuid, user=user)
task_uuid=task_uuid, user=user, interruptible=interruptible)
act.save()
return act
def create_sub(self, code_suffix, task_uuid=None, concurrency_check=True,
readable_name=None, resultant_state=None):
readable_name=None, resultant_state=None,
interruptible=False):
readable_name = _normalize_readable_name(readable_name, code_suffix)
# Check for concurrent activities
......@@ -119,7 +127,7 @@ class InstanceActivity(ActivityModel):
act = InstanceActivity(
activity_code=join_activity_code(self.activity_code, code_suffix),
instance=self.instance, parent=self,
resultant_state=resultant_state,
resultant_state=resultant_state, interruptible=interruptible,
readable_name_data=readable_name.to_dict(), started=timezone.now(),
task_uuid=task_uuid, user=self.user)
act.save()
......@@ -183,13 +191,14 @@ class InstanceActivity(ActivityModel):
@contextmanager
def sub_activity(self, code_suffix, on_abort=None, on_commit=None,
readable_name=None, task_uuid=None,
concurrency_check=True):
concurrency_check=True, interruptible=False):
"""Create a transactional context for a nested instance activity.
"""
if not readable_name:
warn("Set readable_name", stacklevel=3)
act = self.create_sub(code_suffix, task_uuid, concurrency_check,
readable_name=readable_name)
readable_name=readable_name,
interruptible=interruptible)
return activitycontextimpl(act, on_abort=on_abort, on_commit=on_commit)
def get_operation(self):
......
......@@ -123,6 +123,10 @@ class VirtualMachineDescModel(BaseResourceConfigModel):
'format like "%s".') %
'Ubuntu 12.04 LTS Desktop amd64'))
tags = TaggableManager(blank=True, verbose_name=_("tags"))
has_agent = BooleanField(verbose_name=_('has agent'), default=True,
help_text=_(
'If the machine has agent installed, and '
'the manager should wait for its start.'))
class Meta:
abstract = True
......@@ -244,10 +248,6 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel, OperatedMixin,
verbose_name=_('time of delete'),
help_text=_("Proposed time of automatic "
"deletion."))
active_since = DateTimeField(blank=True, null=True,
help_text=_("Time stamp of successful "
"boot report."),
verbose_name=_('active since'))
node = ForeignKey(Node, blank=True, null=True,
related_name='instance_set',
help_text=_("Current hypervisor of this instance."),
......@@ -428,7 +428,8 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel, OperatedMixin,
# prepare parameters
common_fields = ['name', 'description', 'num_cores', 'ram_size',
'max_ram_size', 'arch', 'priority', 'boot_menu',
'raw_data', 'lease', 'access_method', 'system']
'raw_data', 'lease', 'access_method', 'system',
'has_agent']
params = dict(template=template, owner=owner, pw=pwgen())
params.update([(f, getattr(template, f)) for f in common_fields])
params.update(kwargs) # override defaults w/ user supplied values
......@@ -513,7 +514,11 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel, OperatedMixin,
def ipv4(self):
"""Primary IPv4 address of the instance.
"""
return self.primary_host.ipv4 if self.primary_host else None
# return self.primary_host.ipv4 if self.primary_host else None
for i in self.interface_set.all():
if i.host:
return i.host.ipv4
return None
@property
def ipv6(self):
......@@ -528,15 +533,6 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel, OperatedMixin,
return self.primary_host.mac if self.primary_host else None
@property
def uptime(self):
"""Uptime of the instance.
"""
if self.active_since:
return timezone.now() - self.active_since
else:
return timedelta() # zero
@property
def os_type(self):
"""Get the type of the instance's operating system.
"""
......@@ -545,13 +541,6 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel, OperatedMixin,
else:
return self.template.os_type
def get_age(self):
"""Deprecated. Use uptime instead.
Get age of VM in seconds.
"""
return self.uptime.seconds
@property
def waiting(self):
"""Indicates whether the instance's waiting for an operation to finish.
......@@ -603,14 +592,19 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel, OperatedMixin,
port = self.get_connect_port(use_ipv6=use_ipv6)
host = self.get_connect_host(use_ipv6=use_ipv6)
proto = self.access_method
if proto == 'ssh':
proto = 'sshterm'
return ('%(proto)s:cloud:%(pw)s:%(host)s:%(port)d' %
return ('circle:%(proto)s:cloud:%(pw)s:%(host)s:%(port)d' %
{'port': port, 'proto': proto, 'pw': self.pw,
'host': host})
except:
return
@property
def short_hostname(self):
try:
return self.primary_host.hostname
except AttributeError:
return self.vm_name
def get_vm_desc(self):
"""Serialize Instance object to vmdriver.
"""
......
......@@ -34,6 +34,7 @@ from common.models import (
create_readable, humanize_exception, HumanReadableException
)
from common.operations import Operation, register_operation
from manager.scheduler import SchedulerError
from .tasks.local_tasks import (
abortable_async_instance_operation, abortable_async_node_operation,
)
......@@ -41,7 +42,7 @@ from .models import (
Instance, InstanceActivity, InstanceTemplate, Interface, Node,
NodeActivity, pwgen
)
from .tasks import agent_tasks
from .tasks import agent_tasks, local_agent_tasks
from dashboard.store_api import Store, NoStoreException
......@@ -153,6 +154,7 @@ class AddInterfaceOperation(InstanceOperation):
self.rollback(net, activity)
raise
net.deploy()
local_agent_tasks.send_networking_commands(self.instance, activity)
def get_activity_name(self, kwargs):
return create_readable(ugettext_noop("add %(vlan)s interface"),
......@@ -297,16 +299,20 @@ class DeployOperation(InstanceOperation):
"deploy network")):
self.instance.deploy_net()
try:
self.instance.renew(parent_activity=activity)
except:
pass
# Resume vm
with activity.sub_activity(
'booting', readable_name=ugettext_noop(
"boot virtual machine")):
self.instance.resume_vm(timeout=timeout)
try:
self.instance.renew(parent_activity=activity)
except:
pass
if self.instance.has_agent:
activity.sub_activity('os_boot', readable_name=ugettext_noop(
"wait operating system loading"), interruptible=True)
register_operation(DeployOperation)
......@@ -423,8 +429,11 @@ class RebootOperation(InstanceOperation):
required_perms = ()
accept_states = ('RUNNING', )
def _operation(self, timeout=5):
def _operation(self, activity, timeout=5):
self.instance.reboot_vm(timeout=timeout)
if self.instance.has_agent:
activity.sub_activity('os_boot', readable_name=ugettext_noop(
"wait operating system loading"), interruptible=True)
register_operation(RebootOperation)
......@@ -497,8 +506,11 @@ class ResetOperation(InstanceOperation):
required_perms = ()
accept_states = ('RUNNING', )
def _operation(self, timeout=5):
def _operation(self, activity, timeout=5):
self.instance.reset_vm(timeout=timeout)
if self.instance.has_agent:
activity.sub_activity('os_boot', readable_name=ugettext_noop(
"wait operating system loading"), interruptible=True)
register_operation(ResetOperation)
......@@ -619,6 +631,17 @@ class ShutdownOperation(InstanceOperation):
self.instance.yield_node()
self.instance.yield_vnc_port()
def on_abort(self, activity, error):
if isinstance(error, TimeLimitExceeded):
activity.result = humanize_exception(ugettext_noop(
"The virtual machine did not switch off in the provided time "
"limit. Most of the time this is caused by incorrect ACPI "
"settings. You can also try to power off the machine from the "
"operating system manually."), error)
activity.resultant_state = None
else:
super(ShutdownOperation, self).on_abort(activity, error)
register_operation(ShutdownOperation)
......@@ -716,6 +739,9 @@ class WakeUpOperation(InstanceOperation):
return self.instance.status == self.instance.STATUS.SUSPENDED
def on_abort(self, activity, error):
if isinstance(error, SchedulerError):
activity.resultant_state = None
else:
activity.resultant_state = 'ERROR'
def _operation(self, activity, timeout=60):
......@@ -1003,12 +1029,12 @@ class MountStoreOperation(EnsureAgentMixin, InstanceOperation):
except NoStoreException:
raise PermissionDenied # not show the button at all
def _operation(self):
def _operation(self, user):
inst = self.instance
queue = self.instance.get_remote_queue_name("agent")
host = urlsplit(settings.STORE_URL).hostname
username = Store(inst.owner).username
password = inst.owner.profile.smb_password
username = Store(user).username
password = user.profile.smb_password
agent_tasks.mount_store.apply_async(
queue=queue, args=(inst.vm_name, host, username, password))
......
......@@ -76,3 +76,8 @@ def get_keys(vm):
@celery.task(name='agent.send_expiration')
def send_expiration(vm, url):
pass
@celery.task(name='agent.change_ip')
def change_ip(vm, interfaces, dns):
pass
......@@ -19,7 +19,9 @@ 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)
cleanup, update, change_ip)
from firewall.models import Host
import time
from base64 import encodestring
from StringIO import StringIO
......@@ -31,13 +33,11 @@ from celery.result import TimeoutError
from monitor.client import Client
def send_init_commands(instance, act, vm):
def send_init_commands(instance, act):
vm = instance.vm_name
queue = instance.get_remote_queue_name("agent")
with act.sub_activity('cleanup', readable_name=ugettext_noop('cleanup')):
cleanup.apply_async(queue=queue, args=(vm, ))
with act.sub_activity('restart_networking',
readable_name=ugettext_noop('restart networking')):
restart_networking.apply_async(queue=queue, args=(vm, ))
with act.sub_activity('change_password',
readable_name=ugettext_noop('change password')):
change_password.apply_async(queue=queue, args=(vm, instance.pw))
......@@ -46,7 +46,18 @@ def send_init_commands(instance, act, vm):
with act.sub_activity('set_hostname',
readable_name=ugettext_noop('set hostname')):
set_hostname.apply_async(
queue=queue, args=(vm, instance.primary_host.hostname))
queue=queue, args=(vm, instance.short_hostname))
def send_networking_commands(instance, act):
queue = instance.get_remote_queue_name("agent")
with act.sub_activity('change_ip',
readable_name=ugettext_noop('change ip')):
change_ip.apply_async(queue=queue, args=(
instance.vm_name, ) + get_network_configs(instance))
with act.sub_activity('restart_networking',
readable_name=ugettext_noop('restart networking')):
restart_networking.apply_async(queue=queue, args=(instance.vm_name, ))
def create_agent_tar():
......@@ -74,16 +85,22 @@ def agent_started(vm, version=None):
from vm.models import Instance, instance_activity, InstanceActivity
instance = Instance.objects.get(id=int(vm.split('-')[-1]))
queue = instance.get_remote_queue_name("agent")
initialized = InstanceActivity.objects.filter(
instance=instance, activity_code='vm.Instance.agent.cleanup').exists()
initialized = instance.activity_log.filter(
activity_code='vm.Instance.agent.cleanup').exists()
with instance_activity(code_suffix='agent',
readable_name=ugettext_noop('agent'),
concurrency_check=False,
instance=instance) as act:
with act.sub_activity('starting',
readable_name=ugettext_noop('starting')):
pass
for i in InstanceActivity.objects.filter(
instance=instance, activity_code__endswith='.os_boot',
finished__isnull=True):
i.finish(True)
if version and version != settings.AGENT_VERSION:
try:
update_agent(instance, act)
......@@ -94,12 +111,12 @@ def agent_started(vm, version=None):
if not initialized:
measure_boot_time(instance)
send_init_commands(instance, act, vm)
send_init_commands(instance, act)
with act.sub_activity(
'start_access_server',
readable_name=ugettext_noop('start access server')
):
send_networking_commands(instance, act)
with act.sub_activity('start_access_server',
readable_name=ugettext_noop(
'start access server')):
start_access_server.apply_async(queue=queue, args=(vm, ))
......@@ -134,6 +151,13 @@ def agent_stopped(vm):
pass
def get_network_configs(instance):
interfaces = {}
for host in Host.objects.filter(interface__instance=instance):
interfaces[str(host.mac)] = host.get_network_config()
return (interfaces, settings.FIREWALL_SETTINGS['rdns_ip'])
def update_agent(instance, act=None):
if act:
act = act.sub_activity(
......
......@@ -217,6 +217,8 @@ class InstanceActivityTestCase(TestCase):
def test_create_concurrency_check(self):
instance = MagicMock(spec=Instance)
instance.activity_log.filter.return_value.__iter__.return_value = iter(
[MagicMock(spec=InstanceActivity, interruptible=False)])
instance.activity_log.filter.return_value.exists.return_value = True
with self.assertRaises(ActivityInProgressError):
......
......@@ -14,4 +14,3 @@ post-stop script
stop mancelery
stop slowcelery
end script
......@@ -12,4 +12,3 @@ script
. /home/cloud/.virtualenvs/circle/bin/postactivate
exec ./manage.py celery --app=manager.mancelery worker --autoreload --loglevel=info --hostname=mancelery -B -c 10
end script
......@@ -12,4 +12,3 @@ script
. /home/cloud/.virtualenvs/circle/bin/postactivate
exec ./manage.py celery --app=manager.moncelery worker --autoreload --loglevel=info --hostname=moncelery -B -c 3
end script
......@@ -12,4 +12,3 @@ script
. /home/cloud/.virtualenvs/circle/bin/postactivate
exec /home/cloud/.virtualenvs/circle/bin/uwsgi --chdir=/home/cloud/circle/circle -H /home/cloud/.virtualenvs/circle --socket /tmp/uwsgi.sock --wsgi-file circle/wsgi.py --chmod-socket=666
end script
......@@ -14,4 +14,3 @@ script
. /home/cloud/.virtualenvs/circle/bin/postactivate
exec ./manage.py runserver '[::]:8080'
end script
......@@ -12,4 +12,3 @@ script
. /home/cloud/.virtualenvs/circle/bin/postactivate
exec ./manage.py celery --app=manager.slowcelery worker --autoreload --loglevel=info --hostname=slowcelery -B -c 5
end script
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