Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (6.5 kB)

1
# Copyright 2012 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 django.core.management.base import NoArgsCommand, CommandError
35

    
36
from optparse import make_option
37

    
38
from pithos.api.util import get_backend
39
from pithos.backends.modular import CLUSTER_NORMAL, DEFAULT_SOURCE
40
from synnefo.webproject.management import utils
41
from astakosclient.errors import AstakosClientException
42

    
43
ENTITY_KEY = '1'
44

    
45
backend = get_backend()
46

    
47
class Command(NoArgsCommand):
48
    help = "List and reset pithos usage"
49

    
50
    option_list = NoArgsCommand.option_list + (
51
        make_option('--list',
52
                    dest='list',
53
                    action="store_true",
54
                    default=True,
55
                    help="List usage for all or specified user"),
56
        make_option('--reset',
57
                    dest='reset',
58
                    action="store_true",
59
                    default=False,
60
                    help="Reset usage for all or specified users"),
61
        make_option('--diverging',
62
                    dest='diverging',
63
                    action="store_true",
64
                    default=False,
65
                    help=("List or reset diverging usages")),
66
        make_option('--user',
67
                    dest='users',
68
                    action='append',
69
                    metavar='USER_UUID',
70
                    help=("Specify which users --list or --reset applies."
71
                          "This option can be repeated several times."
72
                          "If no user is specified --list or --reset "
73
                          "will be applied globally.")),
74
        make_option(
75
            "--no-headers",
76
            dest="headers",
77
            action="store_false",
78
            default=True,
79
            help="Do not display headers"),
80
        make_option(
81
            "--output-format",
82
            dest="output_format",
83
            metavar="[pretty, csv, json]",
84
            default="pretty",
85
            choices=["pretty", "csv", "json"],
86
            help="Select the output format: pretty [the default], tabs"
87
                 " [tab-separated output], csv [comma-separated output]"),
88

    
89
    )
90

    
91
    def handle_noargs(self, **options):
92
        try:
93
            account_nodes = backend.node.node_accounts(options['users'])
94
            if not account_nodes:
95
                raise CommandError('No users found.')
96

    
97
            db_usage = {}
98
            for path, node in account_nodes:
99
                size = backend.node.node_account_usage(node, CLUSTER_NORMAL)
100
                db_usage[path] = size or 0
101

    
102
            result = backend.quotaholder.service_get_quotas(
103
                backend.quotaholder_token,
104
            )
105

    
106
            qh_usage = {}
107
            resource = 'pithos.diskspace'
108
            pending_list = []
109
            for uuid, d in result.iteritems():
110
                pithos_dict = d.get(DEFAULT_SOURCE, {}).get(resource, {})
111
                pending = pithos_dict.get('pending', 0)
112
                if pending != 0:
113
                    pending_list.append(pending)
114
                    continue
115
                qh_usage[uuid] = pithos_dict.get('usage', 0)
116

    
117
            if pending_list:
118
                self.stdout.write((
119
                    "There are pending commissions for: %s.\n"
120
                    "Reconcile commissions and retry"
121
                    "in order to list/reset their quota.\n"
122
                ) % pending_list)
123

    
124
            headers = ['uuid', 'usage']
125
            table = []
126
            provisions = []
127
            for uuid in db_usage.keys():
128
                try:
129
                    delta = db_usage[uuid] - qh_usage[uuid]
130
                except KeyError:
131
                    self.stdout.write('Unknown holder: %s\n' % uuid)
132
                    continue
133
                else:
134
                    if options['diverging'] and delta == 0:
135
                        continue
136
                    table.append((uuid, db_usage[uuid]))
137
                    provisions.append({"holder": uuid,
138
                                       "source": DEFAULT_SOURCE,
139
                                       "resource": resource,
140
                                       "quantity": delta
141
                    })
142

    
143

    
144
            if options['reset']:
145
                if not provisions:
146
                    raise CommandError('Nothing to reset')
147
                request = {}
148
                request['force'] = True
149
                request['auto_accept'] = True
150
                request['provisions'] = provisions
151
                try:
152
                    serial = backend.quotaholder.issue_commission(
153
                        backend.quotaholder_token, request
154
                    )
155
                except AstakosClientException, e:
156
                    self.stdout.write(e.details)
157
                else:
158
                    backend.quotaholder_serials.insert_many([serial])
159
            elif options['list'] and table:
160
                output_format = options["output_format"]
161
                if output_format != "json" and not options["headers"]:
162
                    headers = None
163
                utils.pprint_table(self.stdout, table, headers, output_format)
164
        finally:
165
            backend.close()