Completed
Push — master ( 8d80e2...82fff3 )
by
unknown
45s
created

get_crash_storage_class()   A

Complexity

Conditions 1

Size

Total Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
c 0
b 0
f 0
dl 0
loc 2
rs 10
1
# coding: utf8
2
3
"""
4
This software is licensed under the Apache 2 license, quoted below.
5
6
Copyright 2014 Crystalnix Limited
7
8
Licensed under the Apache License, Version 2.0 (the "License"); you may not
9
use this file except in compliance with the License. You may obtain a copy of
10
the License at
11
12
    http://www.apache.org/licenses/LICENSE-2.0
13
14
Unless required by applicable law or agreed to in writing, software
15
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17
License for the specific language governing permissions and limitations under
18
the License.
19
"""
20
21
import os
22
import uuid
23
24
from django.db import models
25
from django.db.models.signals import post_save, pre_delete, pre_save
26
from django.dispatch import receiver
27
from django.utils import timezone
28
from django.utils.module_loading import import_string
29
from django.conf import settings
30
31
from celery import signature
32
from jsonfield import JSONField
33
34
from omaha.models import BaseModel
35
from omaha_server.utils import storage_with_spaces_instance
36 View Code Duplication
from crash.managers import CrashManager, SymbolsManager
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
37
38
39
def upload_to(directory, obj, filename):
40
    now = timezone.now()
41
    max_length = 255
42
    path = os.path.join(*map(str, [directory, now.year, now.month,
43
                                   now.day, uuid.uuid4(), filename]))
44
    if len(path) > max_length:
45
        name, ext = os.path.splitext(path)
46
        ext_length = len(ext)
47
        path = name[:max_length-ext_length] + ext
48
    return path
49
50
51
def crash_upload_to(obj, filename):
52
    return upload_to('minidump', obj, filename)
53
54
55
def crash_archive_upload_to(obj, filename):
56
    return upload_to('minidump_archive', obj, filename)
57
58
59
def get_crash_storage_class():
60
    return import_string(getattr(settings, 'CRASH_FILE_STORAGE', settings.DEFAULT_FILE_STORAGE))
61
62
63
crash_storage = get_crash_storage_class()()
64
65
66
class Crash(BaseModel):
67
    upload_file_minidump = models.FileField(upload_to=crash_upload_to, blank=True, null=True,
68
                                            max_length=255, storage=crash_storage)
69
    minidump_size = models.PositiveIntegerField(null=True, blank=True)
70
    archive = models.FileField(upload_to=crash_archive_upload_to, blank=True, null=True,
71
                               max_length=255, storage=crash_storage)
72
    archive_size = models.PositiveIntegerField(null=True, blank=True)
73
    appid = models.CharField(max_length=38, null=True, blank=True)
74
    userid = models.CharField(max_length=38, null=True, blank=True)
75
    meta = JSONField(verbose_name='Meta-information', help_text='JSON format', null=True, blank=True)
76
    stacktrace = models.TextField(null=True, blank=True)
77
    stacktrace_json = JSONField(null=True, blank=True)
78
    signature = models.CharField(max_length=255, db_index=True, null=True, blank=True)
79
    ip = models.GenericIPAddressField(blank=True, null=True, protocol="ipv4")
80
    groupid = models.CharField(max_length=38, null=True, blank=True)
81
    eventid = models.CharField(max_length=38, null=True, blank=True)
82
    os = models.CharField(max_length=32, null=True, blank=True)
83
    build_number = models.CharField(max_length=32, null=True, blank=True)
84
    channel = models.CharField(max_length=32, null=True, blank=True, default='')
85
86
    objects = CrashManager()
87
88
    class Meta(BaseModel.Meta):
89
        verbose_name_plural = 'Crashes'
90
91
    def __unicode__(self):
92
        return u"Crash #{0}".format(self.id) + (" ({0})".format(self.signature) if self.signature else '')
93
94
    @property
95
    def size(self):
96
        return self.archive_size + self.minidump_size
97
98
99
class CrashDescription(BaseModel):
100
    crash = models.OneToOneField(Crash, related_name='crash_description')
101
    summary = models.CharField(max_length=500)
102
    description = models.TextField(null=True, blank=True)
103
104
105
def symbols_upload_to(obj, filename):
106
    sym_filename = os.path.splitext(os.path.basename(obj.debug_file))[0]
107
    sym_filename = '%s.sym' % sym_filename
108
    return os.path.join('symbols', obj.debug_file, obj.debug_id, sym_filename)
109
110
111
class Symbols(BaseModel):
112
    debug_id = models.CharField(verbose_name='Debug ID', max_length=255, db_index=True, null=True, blank=True)
113
    debug_file = models.CharField(verbose_name='Debug file name', max_length=140, null=True, blank=True)
114
    file = models.FileField(upload_to=symbols_upload_to, null=True, storage=storage_with_spaces_instance)
115
    file_size = models.PositiveIntegerField(null=True, blank=True)
116
117
    objects = SymbolsManager()
118
119
    class Meta:
120
        verbose_name_plural = 'Symbols'
121
        unique_together = (
122
            ('debug_id', 'debug_file'),
123
        )
124
125
    @property
126
    def size(self):
127
         return self.file_size
128
129
130
@receiver(pre_save, sender=Crash)
131
def pre_crash_save(sender, instance, *args, **kwargs):
132
    if instance.pk:
133
        old = sender.objects.get(pk=instance.pk)
134
        if old.upload_file_minidump != instance.upload_file_minidump:
135
            old.upload_file_minidump.delete(save=False)
136
            old.minidump_size = 0
137
            old.archive.delete(save=False)
138
            old.archive_size = 0
139
        elif old.archive != instance.archive:
140
            old.archive.delete(save=False)
141
            old.archive_size = 0
142
143
144
@receiver(post_save, sender=Crash)
145
def crash_post_save(sender, instance, created, *args, **kwargs):
146
    if created and instance.upload_file_minidump:
147
        signature("tasks.processing_crash_dump", args=(instance.pk,)).apply_async(queue='private', countdown=1)
148
149
150
@receiver(pre_delete, sender=Crash)
151
def pre_crash_delete(sender, instance, **kwargs):
152
    file_fields = [instance.archive, instance.upload_file_minidump]
153
    for field in file_fields:
154
        storage, name = field.storage, field.name
155
        if name:
156
            storage.delete(name)
157
158
159
@receiver(pre_save, sender=Symbols)
160
def pre_symbol_save(sender, instance, *args, **kwargs):
161
    if instance.pk:
162
        old = sender.objects.get(pk=instance.pk)
163
        if old.file == instance.file:
164
            return
165
        else:
166
            old.file.delete(save=False)
167
            old.file_size = 0
168
169
170
@receiver(pre_delete, sender=Symbols)
171
def pre_symbol_delete(sender, instance, **kwargs):
172
    storage, name = instance.file.storage, instance.file.name
173
    if name:
174
        storage.delete(name)
175