Completed
Push — master ( 646ecf...07a97f )
by
unknown
48s
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
29
from celery import signature
30
from jsonfield import JSONField
31
32
from omaha.models import BaseModel
33
from omaha_server.utils import storage_with_spaces_instance
34
from crash.managers import CrashManager, SymbolsManager
35
36 View Code Duplication
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
37
def upload_to(directory, obj, filename):
38
    now = timezone.now()
39
    max_length = 255
40
    path = os.path.join(*map(str, [directory, now.year, now.month,
41
                                   now.day, uuid.uuid4(), filename]))
42
    if len(path) > max_length:
43
        name, ext = os.path.splitext(path)
44
        ext_length = len(ext)
45
        path = name[:max_length-ext_length] + ext
46
    return path
47
48
49
def crash_upload_to(obj, filename):
50
    return upload_to('minidump', obj, filename)
51
52
53
def crash_archive_upload_to(obj, filename):
54
    return upload_to('minidump_archive', obj, filename)
55
56
57
class Crash(BaseModel):
58
    upload_file_minidump = models.FileField(upload_to=crash_upload_to, blank=True, null=True,
59
                                            max_length=255)
60
    minidump_size = models.PositiveIntegerField(null=True, blank=True)
61
    archive = models.FileField(upload_to=crash_archive_upload_to, blank=True, null=True,
62
                               max_length=255)
63
    archive_size = models.PositiveIntegerField(null=True, blank=True)
64
    appid = models.CharField(max_length=38, null=True, blank=True)
65
    userid = models.CharField(max_length=38, null=True, blank=True)
66
    meta = JSONField(verbose_name='Meta-information', help_text='JSON format', null=True, blank=True)
67
    stacktrace = models.TextField(null=True, blank=True)
68
    stacktrace_json = JSONField(null=True, blank=True)
69
    signature = models.CharField(max_length=255, db_index=True, null=True, blank=True)
70
    ip = models.GenericIPAddressField(blank=True, null=True, protocol="ipv4")
71
    groupid = models.CharField(max_length=38, null=True, blank=True)
72
    eventid = models.CharField(max_length=38, null=True, blank=True)
73
    os = models.CharField(max_length=32, null=True, blank=True)
74
    build_number = models.CharField(max_length=32, null=True, blank=True)
75
    channel = models.CharField(max_length=32, null=True, blank=True, default='')
76
77
    objects = CrashManager()
78
79
    class Meta(BaseModel.Meta):
80
        verbose_name_plural = 'Crashes'
81
82
    def __unicode__(self):
83
        return u"Crash #{0}".format(self.id) + (" ({0})".format(self.signature) if self.signature else '')
84
85
    @property
86
    def size(self):
87
        return self.archive_size + self.minidump_size
88
89
90
class CrashDescription(BaseModel):
91
    crash = models.OneToOneField(Crash, related_name='crash_description')
92
    summary = models.CharField(max_length=500)
93
    description = models.TextField(null=True, blank=True)
94
95
96
def symbols_upload_to(obj, filename):
97
    sym_filename = os.path.splitext(os.path.basename(obj.debug_file))[0]
98
    sym_filename = '%s.sym' % sym_filename
99
    return os.path.join('symbols', obj.debug_file, obj.debug_id, sym_filename)
100
101
102
class Symbols(BaseModel):
103
    debug_id = models.CharField(verbose_name='Debug ID', max_length=255, db_index=True, null=True, blank=True)
104
    debug_file = models.CharField(verbose_name='Debug file name', max_length=140, null=True, blank=True)
105
    file = models.FileField(upload_to=symbols_upload_to, null=True, storage=storage_with_spaces_instance)
106
    file_size = models.PositiveIntegerField(null=True, blank=True)
107
108
    objects = SymbolsManager()
109
110
    class Meta:
111
        verbose_name_plural = 'Symbols'
112
        unique_together = (
113
            ('debug_id', 'debug_file'),
114
        )
115
116
    @property
117
    def size(self):
118
         return self.file_size
119
120
121
@receiver(pre_save, sender=Crash)
122
def pre_crash_save(sender, instance, *args, **kwargs):
123
    if instance.pk:
124
        old = sender.objects.get(pk=instance.pk)
125
        if old.upload_file_minidump != instance.upload_file_minidump:
126
            old.upload_file_minidump.delete(save=False)
127
            old.minidump_size = 0
128
            old.archive.delete(save=False)
129
            old.archive_size = 0
130
        elif old.archive != instance.archive:
131
            old.archive.delete(save=False)
132
            old.archive_size = 0
133
134
135
@receiver(post_save, sender=Crash)
136
def crash_post_save(sender, instance, created, *args, **kwargs):
137
    if created and instance.upload_file_minidump:
138
        signature("tasks.processing_crash_dump", args=(instance.pk,)).apply_async(queue='private', countdown=1)
139
140
141
@receiver(pre_delete, sender=Crash)
142
def pre_crash_delete(sender, instance, **kwargs):
143
    file_fields = [instance.archive, instance.upload_file_minidump]
144
    for field in file_fields:
145
        storage, name = field.storage, field.name
146
        if name:
147
            storage.delete(name)
148
149
150
@receiver(pre_save, sender=Symbols)
151
def pre_symbol_save(sender, instance, *args, **kwargs):
152
    if instance.pk:
153
        old = sender.objects.get(pk=instance.pk)
154
        if old.file == instance.file:
155
            return
156
        else:
157
            old.file.delete(save=False)
158
            old.file_size = 0
159
160
161
@receiver(pre_delete, sender=Symbols)
162
def pre_symbol_delete(sender, instance, **kwargs):
163
    storage, name = instance.file.storage, instance.file.name
164
    if name:
165
        storage.delete(name)
166