Commit 04bbf626 by Őry Máté

Merge branch 'master' into feature-titles

parents 60fedbfc ea3039d6
...@@ -214,6 +214,14 @@ class ActivityModel(TimeStampedModel): ...@@ -214,6 +214,14 @@ class ActivityModel(TimeStampedModel):
self.result_data = None if value is None else value.to_dict() 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() @celery.task()
def compute_cached(method, instance, memcached_seconds, def compute_cached(method, instance, memcached_seconds,
......
...@@ -143,7 +143,7 @@ class VmCustomizeForm(forms.Form): ...@@ -143,7 +143,7 @@ class VmCustomizeForm(forms.Form):
self.template = kwargs.pop("template", None) self.template = kwargs.pop("template", None)
super(VmCustomizeForm, self).__init__(*args, **kwargs) super(VmCustomizeForm, self).__init__(*args, **kwargs)
if self.user.has_perm("vm_set_resouces"): if self.user.has_perm("vm.set_resources"):
self.allowed_fields = tuple(self.fields.keys()) self.allowed_fields = tuple(self.fields.keys())
# set displayed disk and network list # set displayed disk and network list
self.fields['disks'].queryset = self.template.disks.all() self.fields['disks'].queryset = self.template.disks.all()
...@@ -481,7 +481,7 @@ class TemplateForm(forms.ModelForm): ...@@ -481,7 +481,7 @@ class TemplateForm(forms.ModelForm):
else: else:
self.allowed_fields = ( self.allowed_fields = (
'name', 'access_method', 'description', 'system', 'tags', 'name', 'access_method', 'description', 'system', 'tags',
'arch', 'lease') 'arch', 'lease', 'has_agent')
if (self.user.has_perm('vm.change_template_resources') if (self.user.has_perm('vm.change_template_resources')
or not self.instance.pk): or not self.instance.pk):
self.allowed_fields += tuple(set(self.fields.keys()) - self.allowed_fields += tuple(set(self.fields.keys()) -
......
...@@ -261,7 +261,7 @@ def get_or_create_profile(self): ...@@ -261,7 +261,7 @@ def get_or_create_profile(self):
Group.profile = property(get_or_create_profile) Group.profile = property(get_or_create_profile)
def create_profile(sender, user, request, **kwargs): def create_profile(user):
if not user.pk: if not user.pk:
return False return False
profile, created = Profile.objects.get_or_create(user=user) profile, created = Profile.objects.get_or_create(user=user)
...@@ -272,7 +272,11 @@ def create_profile(sender, user, request, **kwargs): ...@@ -272,7 +272,11 @@ def create_profile(sender, user, request, **kwargs):
logger.exception("Can't create user %s", unicode(user)) logger.exception("Can't create user %s", unicode(user))
return created 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'): if hasattr(settings, 'SAML_ORG_ID_ATTRIBUTE'):
logger.debug("Register save_org_id to djangosaml2 pre_user_save") logger.debug("Register save_org_id to djangosaml2 pre_user_save")
......
...@@ -51,6 +51,7 @@ ...@@ -51,6 +51,7 @@
{{ form.req_traits|as_crispy_field }} {{ form.req_traits|as_crispy_field }}
{{ form.description|as_crispy_field }} {{ form.description|as_crispy_field }}
{{ form.system|as_crispy_field }} {{ form.system|as_crispy_field }}
{{ form.has_agent|as_crispy_field }}
</fieldset> </fieldset>
<fieldset> <fieldset>
<legend>{% trans "External resources" %}</legend> <legend>{% trans "External resources" %}</legend>
......
...@@ -91,7 +91,7 @@ from vm.models import ( ...@@ -91,7 +91,7 @@ from vm.models import (
from storage.models import Disk from storage.models import Disk
from firewall.models import Vlan, Host, Rule from firewall.models import Vlan, Host, Rule
from .models import (Favourite, Profile, GroupProfile, FutureMember, from .models import (Favourite, Profile, GroupProfile, FutureMember,
ConnectCommand) ConnectCommand, create_profile)
from .store_api import Store, NoStoreException, NotOkException from .store_api import Store, NoStoreException, NotOkException
...@@ -3288,6 +3288,7 @@ class UserCreationView(LoginRequiredMixin, PermissionRequiredMixin, ...@@ -3288,6 +3288,7 @@ class UserCreationView(LoginRequiredMixin, PermissionRequiredMixin,
self.get_group(group_pk) self.get_group(group_pk)
ret = super(UserCreationView, self).post(*args, **kwargs) ret = super(UserCreationView, self).post(*args, **kwargs)
if self.object: if self.object:
create_profile(self.object)
self.object.groups.add(self.group) self.object.groups.add(self.group)
return redirect( return redirect(
reverse('dashboard.views.group-detail', args=[group_pk])) reverse('dashboard.views.group-detail', args=[group_pk]))
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
from django.forms import ModelForm from django.forms import ModelForm
from django.core.urlresolvers import reverse_lazy from django.core.urlresolvers import reverse_lazy
from django.utils.translation import ugettext_lazy as _
from crispy_forms.helper import FormHelper from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Fieldset, Div, Submit, BaseInput from crispy_forms.layout import Layout, Fieldset, Div, Submit, BaseInput
...@@ -56,8 +57,9 @@ class BlacklistItemForm(ModelForm): ...@@ -56,8 +57,9 @@ class BlacklistItemForm(ModelForm):
) )
), ),
FormActions( FormActions(
Submit('submit', 'Save changes'), Submit('submit', _('Save changes')),
LinkButton('back', 'Back', reverse_lazy('network.blacklist_list')) LinkButton('back', _("Back"),
reverse_lazy('network.blacklist_list'))
) )
) )
...@@ -77,8 +79,8 @@ class DomainForm(ModelForm): ...@@ -77,8 +79,8 @@ class DomainForm(ModelForm):
), ),
), ),
FormActions( FormActions(
Submit('submit', 'Save'), Submit('submit', _('Save')),
LinkButton('back', 'Back', reverse_lazy('network.domain_list')) LinkButton('back', _("Back"), reverse_lazy('network.domain_list'))
) )
) )
...@@ -91,15 +93,15 @@ class GroupForm(ModelForm): ...@@ -91,15 +93,15 @@ class GroupForm(ModelForm):
helper.layout = Layout( helper.layout = Layout(
Div( Div(
Fieldset( Fieldset(
'Identity', '',
'name', 'name',
'description', 'description',
'owner', 'owner',
), ),
), ),
FormActions( FormActions(
Submit('submit', 'Save'), Submit('submit', _('Save')),
LinkButton('back', 'Back', reverse_lazy('network.group_list')) LinkButton('back', _("Back"), reverse_lazy('network.group_list'))
) )
) )
...@@ -112,13 +114,13 @@ class HostForm(ModelForm): ...@@ -112,13 +114,13 @@ class HostForm(ModelForm):
helper.layout = Layout( helper.layout = Layout(
Div( Div(
Fieldset( Fieldset(
'Identity', '',
'hostname', 'hostname',
'reverse', 'reverse',
'mac', 'mac',
), ),
Fieldset( Fieldset(
'Network', _('Network'),
'vlan', 'vlan',
'ipv4', 'ipv4',
'ipv6', 'ipv6',
...@@ -126,7 +128,7 @@ class HostForm(ModelForm): ...@@ -126,7 +128,7 @@ class HostForm(ModelForm):
'external_ipv4', 'external_ipv4',
), ),
Fieldset( Fieldset(
'Information', _('Information'),
'description', 'description',
'location', 'location',
'comment', 'comment',
...@@ -134,8 +136,8 @@ class HostForm(ModelForm): ...@@ -134,8 +136,8 @@ class HostForm(ModelForm):
), ),
), ),
FormActions( FormActions(
Submit('submit', 'Save'), Submit('submit', _('Save')),
LinkButton('back', 'Back', reverse_lazy('network.host_list'))) LinkButton('back', _('Back'), reverse_lazy('network.host_list')))
) )
class Meta: class Meta:
...@@ -159,8 +161,8 @@ class RecordForm(ModelForm): ...@@ -159,8 +161,8 @@ class RecordForm(ModelForm):
) )
), ),
FormActions( FormActions(
Submit('submit', 'Save'), Submit('submit', _("Save")),
LinkButton('back', 'Back', reverse_lazy('network.record_list')) LinkButton('back', _("Back"), reverse_lazy('network.record_list'))
) )
) )
...@@ -173,7 +175,7 @@ class RuleForm(ModelForm): ...@@ -173,7 +175,7 @@ class RuleForm(ModelForm):
helper.layout = Layout( helper.layout = Layout(
Div( Div(
Fieldset( Fieldset(
'Identity', '',
'direction', 'direction',
'description', 'description',
'foreign_network', 'foreign_network',
...@@ -189,7 +191,7 @@ class RuleForm(ModelForm): ...@@ -189,7 +191,7 @@ class RuleForm(ModelForm):
'nat_external_ipv4', 'nat_external_ipv4',
), ),
Fieldset( Fieldset(
'External', _('External'),
'vlan', 'vlan',
'vlangroup', 'vlangroup',
'host', 'host',
...@@ -198,8 +200,8 @@ class RuleForm(ModelForm): ...@@ -198,8 +200,8 @@ class RuleForm(ModelForm):
) )
), ),
FormActions( FormActions(
Submit('submit', 'Save'), Submit('submit', _("Save")),
LinkButton('back', 'Back', reverse_lazy('network.rule_list')) LinkButton('back', _("Back"), reverse_lazy('network.rule_list'))
) )
) )
...@@ -219,8 +221,8 @@ class SwitchPortForm(ModelForm): ...@@ -219,8 +221,8 @@ class SwitchPortForm(ModelForm):
) )
), ),
FormActions( FormActions(
Submit('submit', 'Save'), Submit('submit', _("Save")),
LinkButton('back', 'Back', LinkButton('back', _("Back"),
reverse_lazy('network.switch_port_list')) reverse_lazy('network.switch_port_list'))
) )
) )
...@@ -234,41 +236,42 @@ class VlanForm(ModelForm): ...@@ -234,41 +236,42 @@ class VlanForm(ModelForm):
helper.layout = Layout( helper.layout = Layout(
Div( Div(
Fieldset( Fieldset(
'Identity', '',
'name', 'name',
'vid', 'vid',
'network_type', 'network_type',
'managed', 'managed',
), ),
Fieldset( Fieldset(
'IPv4', _('IPv4'),
'network4', 'network4',
'snat_to', 'snat_to',
'snat_ip', 'snat_ip',
'dhcp_pool', 'dhcp_pool',
), ),
Fieldset( Fieldset(
'IPv6', _('IPv6'),
'network6', 'network6',
'ipv6_template', 'ipv6_template',
'host_ipv6_prefixlen', 'host_ipv6_prefixlen',
), ),
Fieldset( Fieldset(
'Domain name service', _('Domain name service'),
'domain', 'domain',
'reverse_domain', 'reverse_domain',
), ),
Fieldset( Fieldset(
'Info', _('Info'),
'description', 'description',
'comment', 'comment',
'owner',
# 'created_at', # 'created_at',
# 'modified_at', # 'modified_at',
), ),
), ),
FormActions( FormActions(
Submit('submit', 'Save'), Submit('submit', _("Save")),
LinkButton('back', 'Back', reverse_lazy('network.vlan_list')) LinkButton('back', _("Back"), reverse_lazy('network.vlan_list'))
) )
) )
...@@ -289,8 +292,8 @@ class VlanGroupForm(ModelForm): ...@@ -289,8 +292,8 @@ class VlanGroupForm(ModelForm):
) )
), ),
FormActions( FormActions(
Submit('submit', 'Save'), Submit('submit', _("Save")),
LinkButton('back', 'Back', reverse_lazy( LinkButton('back', _("Back"), reverse_lazy(
'network.vlan_group_list')) 'network.vlan_group_list'))
) )
) )
......
...@@ -34,6 +34,7 @@ from .forms import (HostForm, VlanForm, DomainForm, GroupForm, RecordForm, ...@@ -34,6 +34,7 @@ from .forms import (HostForm, VlanForm, DomainForm, GroupForm, RecordForm,
BlacklistItemForm, RuleForm, VlanGroupForm, SwitchPortForm) BlacklistItemForm, RuleForm, VlanGroupForm, SwitchPortForm)
from django.contrib import messages from django.contrib import messages
from django.contrib.messages.views import SuccessMessageMixin
from django.views.generic.edit import FormMixin from django.views.generic.edit import FormMixin
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from braces.views import LoginRequiredMixin, SuperuserRequiredMixin from braces.views import LoginRequiredMixin, SuperuserRequiredMixin
...@@ -45,22 +46,11 @@ from dashboard.views import AclUpdateView ...@@ -45,22 +46,11 @@ from dashboard.views import AclUpdateView
from dashboard.forms import AclUserOrGroupAddForm from dashboard.forms import AclUserOrGroupAddForm
class SuccessMessageMixin(FormMixin): class InitialOwnerMixin(FormMixin):
""" def get_initial(self):
Adds a success message on successful form submission. initial = super(InitialOwnerMixin, self).get_initial()
From django/contrib/messages/views.py@9a85ad89 initial['owner'] = self.request.user
""" return initial
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 IndexView(LoginRequiredMixin, SuperuserRequiredMixin, TemplateView): class IndexView(LoginRequiredMixin, SuperuserRequiredMixin, TemplateView):
...@@ -190,7 +180,7 @@ class DomainDetail(LoginRequiredMixin, SuperuserRequiredMixin, ...@@ -190,7 +180,7 @@ class DomainDetail(LoginRequiredMixin, SuperuserRequiredMixin,
class DomainCreate(LoginRequiredMixin, SuperuserRequiredMixin, class DomainCreate(LoginRequiredMixin, SuperuserRequiredMixin,
SuccessMessageMixin, CreateView): SuccessMessageMixin, InitialOwnerMixin, CreateView):
model = Domain model = Domain
template_name = "network/domain-create.html" template_name = "network/domain-create.html"
form_class = DomainForm form_class = DomainForm
...@@ -274,7 +264,7 @@ class GroupList(LoginRequiredMixin, SuperuserRequiredMixin, SingleTableView): ...@@ -274,7 +264,7 @@ class GroupList(LoginRequiredMixin, SuperuserRequiredMixin, SingleTableView):
class GroupCreate(LoginRequiredMixin, SuperuserRequiredMixin, class GroupCreate(LoginRequiredMixin, SuperuserRequiredMixin,
SuccessMessageMixin, CreateView): SuccessMessageMixin, InitialOwnerMixin, CreateView):
model = Group model = Group
template_name = "network/group-create.html" template_name = "network/group-create.html"
form_class = GroupForm form_class = GroupForm
...@@ -413,7 +403,7 @@ class HostDetail(LoginRequiredMixin, SuperuserRequiredMixin, ...@@ -413,7 +403,7 @@ class HostDetail(LoginRequiredMixin, SuperuserRequiredMixin,
class HostCreate(LoginRequiredMixin, SuperuserRequiredMixin, class HostCreate(LoginRequiredMixin, SuperuserRequiredMixin,
SuccessMessageMixin, CreateView): SuccessMessageMixin, InitialOwnerMixin, CreateView):
model = Host model = Host
template_name = "network/host-create.html" template_name = "network/host-create.html"
form_class = HostForm form_class = HostForm
...@@ -497,7 +487,7 @@ class RecordDetail(LoginRequiredMixin, SuperuserRequiredMixin, ...@@ -497,7 +487,7 @@ class RecordDetail(LoginRequiredMixin, SuperuserRequiredMixin,
class RecordCreate(LoginRequiredMixin, SuperuserRequiredMixin, class RecordCreate(LoginRequiredMixin, SuperuserRequiredMixin,
SuccessMessageMixin, CreateView): SuccessMessageMixin, InitialOwnerMixin, CreateView):
model = Record model = Record
template_name = "network/record-create.html" template_name = "network/record-create.html"
form_class = RecordForm form_class = RecordForm
...@@ -505,21 +495,21 @@ class RecordCreate(LoginRequiredMixin, SuperuserRequiredMixin, ...@@ -505,21 +495,21 @@ class RecordCreate(LoginRequiredMixin, SuperuserRequiredMixin,
success_message = _(u'Successfully created record!') success_message = _(u'Successfully created record!')
def get_initial(self): def get_initial(self):
initial = super(RecordCreate, self).get_initial()
initial['domain'] = self.request.GET.get('domain')
host_pk = self.request.GET.get("host") host_pk = self.request.GET.get("host")
try: try:
host = Host.objects.get(pk=host_pk) host = Host.objects.get(pk=host_pk)
except (Host.DoesNotExist, ValueError): except (Host.DoesNotExist, ValueError):
host = None host = None
initial = {'owner': self.request.user}
if host: if host:
initial.update({ initial.update({
'type': "CNAME", 'type': "CNAME",
'host': host, 'host': host,
'address': host.get_fqdn(), 'address': host.get_fqdn(),
}) })
else:
initial['domain'] = self.request.GET.get('domain')
return initial return initial
...@@ -569,18 +559,19 @@ class RuleDetail(LoginRequiredMixin, SuperuserRequiredMixin, ...@@ -569,18 +559,19 @@ class RuleDetail(LoginRequiredMixin, SuperuserRequiredMixin,
class RuleCreate(LoginRequiredMixin, SuperuserRequiredMixin, class RuleCreate(LoginRequiredMixin, SuperuserRequiredMixin,
SuccessMessageMixin, CreateView): SuccessMessageMixin, InitialOwnerMixin, CreateView):
model = Rule model = Rule
template_name = "network/rule-create.html" template_name = "network/rule-create.html"
form_class = RuleForm form_class = RuleForm
success_message = _(u'Successfully created rule!') success_message = _(u'Successfully created rule!')
def get_initial(self): def get_initial(self):
return { initial = super(RuleCreate, self).get_initial()
# 'owner': 1, initial.update({
'host': self.request.GET.get('host'), 'host': self.request.GET.get('host'),
'hostgroup': self.request.GET.get('hostgroup') 'hostgroup': self.request.GET.get('hostgroup')
} })
return initial
class RuleDelete(LoginRequiredMixin, SuperuserRequiredMixin, DeleteView): class RuleDelete(LoginRequiredMixin, SuperuserRequiredMixin, DeleteView):
...@@ -680,7 +671,7 @@ class VlanDetail(LoginRequiredMixin, SuperuserRequiredMixin, ...@@ -680,7 +671,7 @@ class VlanDetail(LoginRequiredMixin, SuperuserRequiredMixin,
class VlanCreate(LoginRequiredMixin, SuperuserRequiredMixin, class VlanCreate(LoginRequiredMixin, SuperuserRequiredMixin,
SuccessMessageMixin, CreateView): SuccessMessageMixin, InitialOwnerMixin, CreateView):
model = Vlan model = Vlan
template_name = "network/vlan-create.html" template_name = "network/vlan-create.html"
form_class = VlanForm form_class = VlanForm
...@@ -760,7 +751,7 @@ class VlanGroupDetail(LoginRequiredMixin, SuperuserRequiredMixin, ...@@ -760,7 +751,7 @@ class VlanGroupDetail(LoginRequiredMixin, SuperuserRequiredMixin,
class VlanGroupCreate(LoginRequiredMixin, SuperuserRequiredMixin, class VlanGroupCreate(LoginRequiredMixin, SuperuserRequiredMixin,
SuccessMessageMixin, CreateView): SuccessMessageMixin, InitialOwnerMixin, CreateView):
model = VlanGroup model = VlanGroup
template_name = "network/vlan-group-create.html" template_name = "network/vlan-group-create.html"
form_class = VlanGroupForm form_class = VlanGroupForm
......
...@@ -367,7 +367,8 @@ class Disk(TimeStampedModel): ...@@ -367,7 +367,8 @@ class Disk(TimeStampedModel):
disk = cls.__create(user, params) disk = cls.__create(user, params)
disk.clean() disk.clean()
disk.save() disk.save()
logger.debug("Disk created: %s", params) logger.debug(u"Disk created from: %s",
unicode(params.get("base", "nobase")))
return disk return disk
@classmethod @classmethod
......
# -*- 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 ...@@ -24,7 +24,7 @@ from celery.signals import worker_ready
from celery.contrib.abortable import AbortableAsyncResult from celery.contrib.abortable import AbortableAsyncResult
from django.core.urlresolvers import reverse 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 import timezone
from django.utils.translation import ugettext_lazy as _, ugettext_noop from django.utils.translation import ugettext_lazy as _, ugettext_noop
...@@ -70,6 +70,8 @@ class InstanceActivity(ActivityModel): ...@@ -70,6 +70,8 @@ class InstanceActivity(ActivityModel):
help_text=_('Instance this activity works on.'), help_text=_('Instance this activity works on.'),
verbose_name=_('instance')) verbose_name=_('instance'))
resultant_state = CharField(blank=True, max_length=20, null=True) resultant_state = CharField(blank=True, max_length=20, null=True)
interruptible = BooleanField(default=False, help_text=_(
'Other activities can interrupt this one.'))
class Meta: class Meta:
app_label = 'vm' app_label = 'vm'
...@@ -91,24 +93,30 @@ class InstanceActivity(ActivityModel): ...@@ -91,24 +93,30 @@ class InstanceActivity(ActivityModel):
@classmethod @classmethod
def create(cls, code_suffix, instance, task_uuid=None, user=None, def create(cls, code_suffix, instance, task_uuid=None, user=None,
concurrency_check=True, readable_name=None, concurrency_check=True, readable_name=None,
resultant_state=None): resultant_state=None, interruptible=False):
readable_name = _normalize_readable_name(readable_name, code_suffix) readable_name = _normalize_readable_name(readable_name, code_suffix)
# Check for concurrent activities # Check for concurrent activities
active_activities = instance.activity_log.filter(finished__isnull=True) active_activities = instance.activity_log.filter(finished__isnull=True)
if concurrency_check and active_activities.exists(): if concurrency_check and active_activities.exists():
raise ActivityInProgressError.create(active_activities[0]) for i in active_activities:
if i.interruptible:
activity_code = join_activity_code(cls.ACTIVITY_CODE_BASE, code_suffix) i.finish(False, result=ugettext_noop(
"Interrupted by other activity."))
else:
raise ActivityInProgressError.create(i)
activity_code = cls.construct_activity_code(code_suffix)
act = cls(activity_code=activity_code, instance=instance, parent=None, act = cls(activity_code=activity_code, instance=instance, parent=None,
resultant_state=resultant_state, started=timezone.now(), resultant_state=resultant_state, started=timezone.now(),
readable_name_data=readable_name.to_dict(), readable_name_data=readable_name.to_dict(),
task_uuid=task_uuid, user=user) task_uuid=task_uuid, user=user, interruptible=interruptible)
act.save() act.save()
return act return act
def create_sub(self, code_suffix, task_uuid=None, concurrency_check=True, 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) readable_name = _normalize_readable_name(readable_name, code_suffix)
# Check for concurrent activities # Check for concurrent activities
...@@ -119,7 +127,7 @@ class InstanceActivity(ActivityModel): ...@@ -119,7 +127,7 @@ class InstanceActivity(ActivityModel):
act = InstanceActivity( act = InstanceActivity(
activity_code=join_activity_code(self.activity_code, code_suffix), activity_code=join_activity_code(self.activity_code, code_suffix),
instance=self.instance, parent=self, 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(), readable_name_data=readable_name.to_dict(), started=timezone.now(),
task_uuid=task_uuid, user=self.user) task_uuid=task_uuid, user=self.user)
act.save() act.save()
...@@ -183,13 +191,14 @@ class InstanceActivity(ActivityModel): ...@@ -183,13 +191,14 @@ class InstanceActivity(ActivityModel):
@contextmanager @contextmanager
def sub_activity(self, code_suffix, on_abort=None, on_commit=None, def sub_activity(self, code_suffix, on_abort=None, on_commit=None,
readable_name=None, task_uuid=None, readable_name=None, task_uuid=None,
concurrency_check=True): concurrency_check=True, interruptible=False):
"""Create a transactional context for a nested instance activity. """Create a transactional context for a nested instance activity.
""" """
if not readable_name: if not readable_name:
warn("Set readable_name", stacklevel=3) warn("Set readable_name", stacklevel=3)
act = self.create_sub(code_suffix, task_uuid, concurrency_check, 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) return activitycontextimpl(act, on_abort=on_abort, on_commit=on_commit)
def get_operation(self): def get_operation(self):
......
...@@ -123,6 +123,10 @@ class VirtualMachineDescModel(BaseResourceConfigModel): ...@@ -123,6 +123,10 @@ class VirtualMachineDescModel(BaseResourceConfigModel):
'format like "%s".') % 'format like "%s".') %
'Ubuntu 12.04 LTS Desktop amd64')) 'Ubuntu 12.04 LTS Desktop amd64'))
tags = TaggableManager(blank=True, verbose_name=_("tags")) 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: class Meta:
abstract = True abstract = True
...@@ -424,7 +428,8 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel, OperatedMixin, ...@@ -424,7 +428,8 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel, OperatedMixin,
# prepare parameters # prepare parameters
common_fields = ['name', 'description', 'num_cores', 'ram_size', common_fields = ['name', 'description', 'num_cores', 'ram_size',
'max_ram_size', 'arch', 'priority', 'boot_menu', '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 = dict(template=template, owner=owner, pw=pwgen())
params.update([(f, getattr(template, f)) for f in common_fields]) params.update([(f, getattr(template, f)) for f in common_fields])
params.update(kwargs) # override defaults w/ user supplied values params.update(kwargs) # override defaults w/ user supplied values
......
...@@ -299,16 +299,20 @@ class DeployOperation(InstanceOperation): ...@@ -299,16 +299,20 @@ class DeployOperation(InstanceOperation):
"deploy network")): "deploy network")):
self.instance.deploy_net() self.instance.deploy_net()
try:
self.instance.renew(parent_activity=activity)
except:
pass
# Resume vm # Resume vm
with activity.sub_activity( with activity.sub_activity(
'booting', readable_name=ugettext_noop( 'booting', readable_name=ugettext_noop(
"boot virtual machine")): "boot virtual machine")):
self.instance.resume_vm(timeout=timeout) self.instance.resume_vm(timeout=timeout)
try: if self.instance.has_agent:
self.instance.renew(parent_activity=activity) activity.sub_activity('os_boot', readable_name=ugettext_noop(
except: "wait operating system loading"), interruptible=True)
pass
register_operation(DeployOperation) register_operation(DeployOperation)
...@@ -425,8 +429,11 @@ class RebootOperation(InstanceOperation): ...@@ -425,8 +429,11 @@ class RebootOperation(InstanceOperation):
required_perms = () required_perms = ()
accept_states = ('RUNNING', ) accept_states = ('RUNNING', )
def _operation(self, timeout=5): def _operation(self, activity, timeout=5):
self.instance.reboot_vm(timeout=timeout) 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) register_operation(RebootOperation)
...@@ -499,8 +506,11 @@ class ResetOperation(InstanceOperation): ...@@ -499,8 +506,11 @@ class ResetOperation(InstanceOperation):
required_perms = () required_perms = ()
accept_states = ('RUNNING', ) accept_states = ('RUNNING', )
def _operation(self, timeout=5): def _operation(self, activity, timeout=5):
self.instance.reset_vm(timeout=timeout) 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) register_operation(ResetOperation)
......
...@@ -85,16 +85,22 @@ def agent_started(vm, version=None): ...@@ -85,16 +85,22 @@ def agent_started(vm, version=None):
from vm.models import Instance, instance_activity, InstanceActivity from vm.models import Instance, instance_activity, InstanceActivity
instance = Instance.objects.get(id=int(vm.split('-')[-1])) instance = Instance.objects.get(id=int(vm.split('-')[-1]))
queue = instance.get_remote_queue_name("agent") queue = instance.get_remote_queue_name("agent")
initialized = InstanceActivity.objects.filter( initialized = instance.activity_log.filter(
instance=instance, activity_code='vm.Instance.agent.cleanup').exists() activity_code='vm.Instance.agent.cleanup').exists()
with instance_activity(code_suffix='agent', with instance_activity(code_suffix='agent',
readable_name=ugettext_noop('agent'), readable_name=ugettext_noop('agent'),
concurrency_check=False,
instance=instance) as act: instance=instance) as act:
with act.sub_activity('starting', with act.sub_activity('starting',
readable_name=ugettext_noop('starting')): readable_name=ugettext_noop('starting')):
pass 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: if version and version != settings.AGENT_VERSION:
try: try:
update_agent(instance, act) update_agent(instance, act)
...@@ -108,10 +114,9 @@ def agent_started(vm, version=None): ...@@ -108,10 +114,9 @@ def agent_started(vm, version=None):
send_init_commands(instance, act) send_init_commands(instance, act)
send_networking_commands(instance, act) send_networking_commands(instance, act)
with act.sub_activity( with act.sub_activity('start_access_server',
'start_access_server', readable_name=ugettext_noop(
readable_name=ugettext_noop('start access server') 'start access server')):
):
start_access_server.apply_async(queue=queue, args=(vm, )) start_access_server.apply_async(queue=queue, args=(vm, ))
......
...@@ -217,6 +217,8 @@ class InstanceActivityTestCase(TestCase): ...@@ -217,6 +217,8 @@ class InstanceActivityTestCase(TestCase):
def test_create_concurrency_check(self): def test_create_concurrency_check(self):
instance = MagicMock(spec=Instance) 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 instance.activity_log.filter.return_value.exists.return_value = True
with self.assertRaises(ActivityInProgressError): with self.assertRaises(ActivityInProgressError):
......
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