Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-app / pithos / api / management / commands / reconcile-resources-pithos.py @ b6426ead

History | View | Annotate | Download (6.1 kB)

1
# Copyright 2012, 2013 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

    
34
from datetime import datetime
35
from django.core.management.base import CommandError
36

    
37
from optparse import make_option
38

    
39
from pithos.api.util import get_backend
40

    
41
from snf_django.management import utils
42

    
43
from snf_django.management.commands import SynnefoCommand
44
from astakosclient.errors import QuotaLimit, NotFound
45
from snf_django.utils import reconcile
46

    
47
backend = get_backend()
48
RESOURCES = ['pithos.diskspace']
49

    
50

    
51
class Command(SynnefoCommand):
52
    help = """Reconcile resource usage of Astakos with Pithos DB.
53

54
    Detect unsynchronized usage between Astakos and Pithos DB resources and
55
    synchronize them if specified so.
56

57
    """
58
    option_list = SynnefoCommand.option_list + (
59
        make_option("--userid", dest="userid",
60
                    default=None,
61
                    help="Reconcile resources only for this user"),
62
        make_option("--project",
63
                    help="Reconcile resources only for this project"),
64
        make_option("--fix", dest="fix",
65
                    default=False,
66
                    action="store_true",
67
                    help="Synchronize Astakos quotas with Pithos DB."),
68
        make_option("--force",
69
                    default=False,
70
                    action="store_true",
71
                    help="Override Astakos quotas. Force Astakos to impose "
72
                         "the Pithos quota, independently of their value.")
73
    )
74

    
75
    def handle_noargs(self, **options):
76
        write = self.stdout.write
77
        try:
78
            backend.pre_exec()
79
            userid = options['userid']
80
            project = options['project']
81

    
82
            # Get holding from Pithos DB
83
            db_usage = backend.node.node_account_usage(userid, project)
84
            db_project_usage = backend.node.node_project_usage(project)
85

    
86
            users = set(db_usage.keys())
87
            if userid and userid not in users:
88
                if backend._lookup_account(userid) is None:
89
                    write("User '%s' does not exist in DB!\n" % userid)
90
                    return
91

    
92
            # Get holding from Quotaholder
93
            try:
94
                qh_result = backend.astakosclient.service_get_quotas(userid)
95
            except NotFound:
96
                write("User '%s' does not exist in Quotaholder!\n" % userid)
97
                return
98

    
99
            try:
100
                qh_project_result = \
101
                    backend.astakosclient.service_get_project_quotas(project)
102
            except NotFound:
103
                write("Project '%s' does not exist in Quotaholder!\n" %
104
                      project)
105

    
106
            unsynced_users, users_pending, users_unknown =\
107
                reconcile.check_users(self.stderr, RESOURCES,
108
                                      db_usage, qh_result)
109

    
110
            unsynced_projects, projects_pending, projects_unknown =\
111
                reconcile.check_projects(self.stderr, RESOURCES,
112
                                         db_project_usage, qh_project_result)
113
            pending_exists = users_pending or projects_pending
114
            unknown_exists = users_unknown or projects_unknown
115

    
116
            headers = ("Type", "Holder", "Source", "Resource",
117
                       "Database", "Quotaholder")
118
            unsynced = unsynced_users + unsynced_projects
119
            if unsynced:
120
                utils.pprint_table(self.stdout, unsynced, headers)
121
                if options["fix"]:
122
                    force = options["force"]
123
                    name = ("client: reconcile-resources-pithos, time: %s"
124
                            % datetime.now())
125
                    user_provisions = reconcile.create_user_provisions(
126
                        unsynced_users)
127
                    project_provisions = reconcile.create_project_provisions(
128
                        unsynced_projects)
129
                    try:
130
                        backend.astakosclient.issue_commission_generic(
131
                            user_provisions, project_provisions, name=name,
132
                            force=force, auto_accept=True)
133
                    except QuotaLimit:
134
                        write("Reconciling failed because a limit has been "
135
                              "reached. Use --force to ignore the check.\n")
136
                        return
137
                    write("Fixed unsynced resources\n")
138

    
139
            if pending_exists:
140
                write("Found pending commissions. Run 'snf-manage"
141
                      " reconcile-commissions-pithos'\n")
142
            elif not (unsynced or unknown_exists):
143
                write("Everything in sync.\n")
144
        except BaseException as e:
145
            backend.post_exec(False)
146
            raise CommandError(e)
147
        else:
148
            backend.post_exec(True)
149
        finally:
150
            backend.close()