Statistics
| Branch: | Tag: | Revision:

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

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 NoArgsCommand, 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 astakosclient.errors import QuotaLimit, NotFound
44
from snf_django.utils import reconcile
45

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

    
49

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

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

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

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

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

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

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

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

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

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

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

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