Revision 989576a6
b/snf-pithos-app/pithos/api/management/commands/pithos-usage.py | ||
---|---|---|
38 | 38 |
from sqlalchemy import func |
39 | 39 |
from sqlalchemy.sql import select, and_, or_ |
40 | 40 |
|
41 |
from synnefo.util.number import strbigdec |
|
42 |
|
|
43 | 41 |
from pithos.api.util import get_backend |
44 | 42 |
from pithos.backends.modular import ( |
45 | 43 |
CLUSTER_NORMAL, CLUSTER_HISTORY, CLUSTER_DELETED |
46 | 44 |
) |
47 | 45 |
clusters = (CLUSTER_NORMAL, CLUSTER_HISTORY, CLUSTER_DELETED) |
48 | 46 |
|
49 |
Statistics = namedtuple('Statistics', ('node', 'path', 'size', 'cluster')) |
|
47 |
Usage = namedtuple('Usage', ('node', 'path', 'size', 'cluster')) |
|
48 |
GetQuota = namedtuple('GetQuota', ('entity', 'resource', 'key')) |
|
50 | 49 |
|
51 | 50 |
class ResetHoldingPayload(namedtuple('ResetHoldingPayload', ( |
52 | 51 |
'entity', 'resource', 'key', 'imported', 'exported', 'returned', 'released' |
... | ... | |
63 | 62 |
table = {} |
64 | 63 |
table['nodes'] = backend.node.nodes |
65 | 64 |
table['versions'] = backend.node.versions |
66 |
table['statistics'] = backend.node.statistics |
|
67 | 65 |
table['policy'] = backend.node.policy |
68 | 66 |
conn = backend.node.conn |
69 | 67 |
|
... | ... | |
75 | 73 |
s = s.where(table['nodes'].c.path.in_(users)) |
76 | 74 |
return conn.execute(s).fetchall() |
77 | 75 |
|
78 |
def _compute_statistics(nodes):
|
|
79 |
statistics = []
|
|
80 |
append = statistics.append
|
|
76 |
def _compute_usage(nodes):
|
|
77 |
usage = []
|
|
78 |
append = usage.append
|
|
81 | 79 |
for path, node in nodes: |
82 | 80 |
select_children = select( |
83 | 81 |
[table['nodes'].c.node]).where(table['nodes'].c.parent == node) |
... | ... | |
96 | 94 |
size = d2[CLUSTER_NORMAL] |
97 | 95 |
except KeyError: |
98 | 96 |
size = 0 |
99 |
append(Statistics(
|
|
97 |
append(Usage(
|
|
100 | 98 |
node=node, |
101 | 99 |
path=path, |
102 | 100 |
size=size, |
103 | 101 |
cluster=CLUSTER_NORMAL)) |
104 |
return statistics |
|
105 |
|
|
106 |
def _verify_statistics(item): |
|
107 |
"""Verify statistics""" |
|
108 |
s = select([table['statistics'].c.size]) |
|
109 |
s = s.where(table['statistics'].c.node == item.node) |
|
110 |
s = s.where(table['statistics'].c.cluster == item.cluster) |
|
111 |
db_item = conn.execute(s).fetchone() |
|
112 |
if not db_item: |
|
113 |
return |
|
114 |
try: |
|
115 |
assert item.size == db_item.size, \ |
|
116 |
'%d[%s][%d], size: %d != %d' % ( |
|
117 |
item.node, item.path, item.cluster, |
|
118 |
item.size, db_item.size) |
|
119 |
except AssertionError, e: |
|
120 |
print e |
|
121 |
|
|
122 |
def _prepare_reset_holding(statistics, verify=False): |
|
123 |
"""Verify statistics and set quotaholder user usage""" |
|
102 |
return usage |
|
103 |
|
|
104 |
def _get_quotaholder_usage(usage): |
|
105 |
payload = [] |
|
106 |
append = payload.append |
|
107 |
[append(GetQuota( |
|
108 |
entity=item.path, |
|
109 |
resource='pithos+.diskspace', |
|
110 |
key=ENTITY_KEY |
|
111 |
)) for item in usage] |
|
112 |
|
|
113 |
result = backend.quotaholder.get_quota( |
|
114 |
context={}, clientkey='pithos', get_quota=payload |
|
115 |
) |
|
116 |
return dict((entity, imported - exported + returned - released) for ( |
|
117 |
entity, resource, quantity, capacity, import_limit, export_limit, |
|
118 |
imported, exported, returned, released, flags |
|
119 |
) in result) |
|
120 |
|
|
121 |
|
|
122 |
def _prepare_reset_holding(usage, only_diverging=False): |
|
123 |
"""Verify usage and set quotaholder user usage""" |
|
124 | 124 |
reset_holding = [] |
125 | 125 |
append = reset_holding.append |
126 |
for item in statistics: |
|
127 |
if verify: |
|
128 |
_verify_statistics(item) |
|
126 |
|
|
127 |
quotaholder_usage = {} |
|
128 |
if only_diverging: |
|
129 |
quotaholder_usage = _get_quotaholder_usage(usage) |
|
130 |
|
|
131 |
for item in(usage): |
|
132 |
if only_diverging and quotaholder_usage.get(item.path) == item.size: |
|
133 |
continue |
|
134 |
|
|
129 | 135 |
if item.cluster == CLUSTER_NORMAL: |
130 | 136 |
append(ResetHoldingPayload( |
131 | 137 |
entity=item.path, |
... | ... | |
152 | 158 |
action="store_true", |
153 | 159 |
default=False, |
154 | 160 |
help="Reset usage for all or specified users"), |
155 |
make_option('--verify',
|
|
156 |
dest='verify',
|
|
161 |
make_option('--diverging',
|
|
162 |
dest='diverging',
|
|
157 | 163 |
action="store_true", |
158 | 164 |
default=False, |
159 |
help=("Verify statistics consistency for all " |
|
160 |
"or specified users")), |
|
165 |
help=("List or reset diverging usages")), |
|
161 | 166 |
make_option('--user', |
162 | 167 |
dest='users', |
163 | 168 |
action='append', |
164 | 169 |
metavar='USER_UUID', |
165 |
help="Specify which users --list or --reset applies. This option can be repeated several times. If no user is specified --list or --reset will be applied globally."), |
|
170 |
help=("Specify which users --list or --reset applies.", |
|
171 |
"This option can be repeated several times.", |
|
172 |
"If no user is specified --list or --reset will be applied globally.")), |
|
166 | 173 |
) |
167 | 174 |
|
168 | 175 |
def handle_noargs(self, **options): |
169 | 176 |
try: |
177 |
user_nodes = _retrieve_user_nodes(options['users']) |
|
178 |
if not user_nodes: |
|
179 |
raise CommandError('No users found.') |
|
180 |
usage = _compute_usage(user_nodes) |
|
181 |
reset_holding = _prepare_reset_holding( |
|
182 |
usage, only_diverging=options['diverging'] |
|
183 |
) |
|
184 |
|
|
170 | 185 |
if options['list']: |
171 |
user_nodes = _retrieve_user_nodes(options['users']) |
|
172 |
if not user_nodes: |
|
173 |
raise CommandError('No users found.') |
|
174 |
statistics = _compute_statistics(user_nodes) |
|
175 |
reset_holding = _prepare_reset_holding( |
|
176 |
statistics, verify=options['verify'] |
|
177 |
) |
|
178 | 186 |
print '\n'.join([str(i) for i in reset_holding]) |
179 | 187 |
|
180 | 188 |
if options['reset']: |
Also available in: Unified diff