~james-w/python-oops-tools/prod-deploy

« back to all changes in this revision

Viewing changes to src/oopstools/scripts/prune.py

  • Committer: Robert Collins
  • Date: 2011-11-21 03:42:03 UTC
  • mto: This revision was merged to the branch mainline in revision 23.
  • Revision ID: robertc@robertcollins.net-20111121034203-ek437opa2fbjjloq
Implement crude pruning for the DB records. Currently untested.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright 2011 Canonical Ltd.  All rights reserved.
 
2
#
 
3
# This program is free software: you can redistribute it and/or modify
 
4
# it under the terms of the GNU Affero General Public License as published by
 
5
# the Free Software Foundation, either version 3 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU Affero General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU Affero General Public License
 
14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
15
 
 
16
# Delete DB records of OOPSes that have no bug reports for them.
 
17
 
 
18
__metaclass__ = type
 
19
 
 
20
import datetime
 
21
import logging
 
22
import optparse
 
23
import sys
 
24
from textwrap import dedent
 
25
 
 
26
from oops_datedir_repo.prune import LaunchpadTracker
 
27
from pytz import utc
 
28
 
 
29
from oopstools.oops.models import (
 
30
    Oops,
 
31
    PruneInfo,
 
32
    )
 
33
 
 
34
 
 
35
def main(argv=None, tracker=LaunchpadTracker, logging=logging):
 
36
    """Console script entry point."""
 
37
    if argv is None:
 
38
        argv = sys.argv
 
39
    usage = dedent("""\
 
40
        %prog [options]
 
41
 
 
42
        The following options must be supplied:
 
43
        Either
 
44
         --project
 
45
        or
 
46
         --projectgroup
 
47
 
 
48
        e.g.
 
49
        %prog --projectgroup launchpad-project
 
50
 
 
51
        Will process every member project of launchpad-project.
 
52
 
 
53
        When run this program will ask Launchpad for OOPS references made since
 
54
        the last date it pruned up to, with an upper limit of one week from
 
55
        today. It then looks in the repository for all oopses created during
 
56
        that date range, and if they are not in the set returned by Launchpad,
 
57
        deletes them. If the repository has never been pruned before, it will
 
58
        pick the earliest date present in the repository as the start date.
 
59
        """)
 
60
    description = \
 
61
        "Delete OOPS reports that are not referenced in a bug tracker."
 
62
    parser = optparse.OptionParser(
 
63
        description=description, usage=usage)
 
64
    parser.add_option('--project',
 
65
        help="Launchpad project to find references in.")
 
66
    parser.add_option('--projectgroup',
 
67
        help="Launchpad project group to find references in.")
 
68
    parser.add_option(
 
69
        '--lpinstance', help="Launchpad instance to use", default="production")
 
70
    options, args = parser.parse_args(argv[1:])
 
71
    def needed(*optnames):
 
72
        present = set()
 
73
        for optname in optnames:
 
74
            if getattr(options, optname, None) is not None:
 
75
                present.add(optname)
 
76
        if not present:
 
77
            if len(optnames) == 1:
 
78
                raise ValueError('Option "%s" must be supplied' % optname)
 
79
            else:
 
80
                raise ValueError(
 
81
                    'One of options %s must be supplied' % (optnames,))
 
82
        elif len(present) != 1:
 
83
            raise ValueError(
 
84
                    'Only one of options %s can be supplied' % (optnames,))
 
85
    needed('project', 'projectgroup')
 
86
    logging.basicConfig(
 
87
        filename='prune.log', filemode='w', level=logging.DEBUG)
 
88
    one_week = datetime.timedelta(weeks=1)
 
89
    one_day = datetime.timedelta(days=1)
 
90
    # Only prune OOPS reports more than one week old.
 
91
    prune_until = datetime.datetime.now(utc) - one_week
 
92
    # Ignore OOPS reports we already found references for - older than the last
 
93
    # prune date.
 
94
    try:
 
95
        info = PruneInfo.objects.all()[0]
 
96
    except IndexError:
 
97
        # Never been pruned.
 
98
        try:
 
99
            oldest_oops = Oops.objects.order_by('id')[0]
 
100
        except IndexError:
 
101
            # And has no oopses
 
102
            return 0
 
103
        info = PruneInfo(pruned_until=oldest_oops.date-one_day)
 
104
        info.save()
 
105
    prune_from = info.pruned_until
 
106
    if prune_from.tzinfo is None:
 
107
        # Workaround django tz handling bug:
 
108
        # https://code.djangoproject.com/ticket/17062
 
109
        prune_from = prune_from.replace(tzinfo=utc)
 
110
    # The tracker finds all the references for the selected dates.
 
111
    finder = tracker(options)
 
112
    references = finder.find_oops_references(
 
113
        prune_from, prune_until, options.project, options.projectgroup)
 
114
    # Then we can delete the unreferenced oopses.
 
115
    PruneInfo.prune_unreferenced(prune_from, prune_until, references)
 
116
    # And finally save the fact we have scanned up to the selected date.
 
117
    info.pruned_until = prune_until
 
118
    info.save()
 
119
    return 0