Revision b1f6aea8

b/snf-django-lib/snf_django/utils/reconcile.py
1
# Copyright 2014 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

  
35
def strcontext(user):
36
    if user is None:
37
        return ""
38
    return "user: %s, " % user
39

  
40

  
41
def get_qh_values(qh_values, user=None):
42
    prefix = "" if user is not None else "project_"
43
    try:
44
        usage = qh_values[prefix+"usage"]
45
        pending = qh_values[prefix+"pending"]
46
    except KeyError:
47
        raise AttributeError("Malformed quota response.")
48
    return usage, pending
49

  
50

  
51
def check_projects(stderr, resources, db_usage, qh_usage, user=None):
52
    write = stderr.write
53
    unsynced = []
54
    pending_exists = False
55
    unknown_exists = False
56

  
57
    projects = set(db_usage.keys())
58
    projects.update(qh_usage.keys())
59

  
60
    for project in projects:
61
        db_project_usage = db_usage.get(project, {})
62
        try:
63
            qh_project_usage = qh_usage[project]
64
        except KeyError:
65
            write("No holdings for %sproject: %s.\n"
66
                  % (strcontext(user), project))
67
            unknown_exists = True
68
            continue
69

  
70
        for resource in resources:
71
            db_value = db_project_usage.get(resource, 0)
72
            try:
73
                qh_values = qh_project_usage[resource]
74
            except KeyError:
75
                write("No holding for %sproject: %s, resource: %s.\n"
76
                      % (strcontext(user), project, resource))
77
                continue
78

  
79
            qh_value, qh_pending = get_qh_values(qh_values, user=user)
80
            if qh_pending:
81
                write("Pending commission for %sproject: %s, resource: %s.\n"
82
                      % (strcontext(user), project, resource))
83
                pending_exists = True
84
                continue
85
            if db_value != qh_value:
86
                tail = (resource, db_value, qh_value)
87
                head = (("project", project, None) if user is None
88
                        else ("user", user, project))
89
                unsynced.append(head + tail)
90
    return unsynced, pending_exists, unknown_exists
91

  
92

  
93
def check_users(stderr, resources, db_usage, qh_usage):
94
    write = stderr.write
95
    unsynced = []
96
    pending_exists = False
97
    unknown_exists = False
98

  
99
    users = set(db_usage.keys())
100
    users.update(qh_usage.keys())
101
    users.discard(None)
102

  
103
    for user in users:
104
        db_user_usage = db_usage.get(user, {})
105
        try:
106
            qh_user_usage = qh_usage[user]
107
        except KeyError:
108
            write("No holdings for user: %s.\n" % user)
109
            unknown_exists = True
110
            continue
111
        uns, pend, unkn = check_projects(stderr, resources,
112
                                         db_user_usage, qh_user_usage,
113
                                         user=user)
114
        unsynced += uns
115
        pending_exists = pending_exists or pend
116
        unknown_exists = unknown_exists or unkn
117
    return unsynced, pending_exists, unknown_exists
118

  
119

  
120
def create_user_provisions(provision_list):
121
    provisions = {}
122
    for _, holder, source, resource, db_value, qh_value in provision_list:
123
        provisions[(holder, source, resource)] = db_value - qh_value
124
    return provisions
125

  
126

  
127
def create_project_provisions(provision_list):
128
    provisions = {}
129
    for _, holder, _, resource, db_value, qh_value in provision_list:
130
        provisions[(holder, resource)] = db_value - qh_value
131
    return provisions

Also available in: Unified diff