Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (6.4 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
backend = get_backend()
44

    
45
class Command(NoArgsCommand):
46
    help = "List and reset pithos usage"
47

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

    
87
    )
88

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

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

    
100
            result = backend.astakosclient.service_get_quotas(
101
                backend.service_token,
102
            )
103

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

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

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

    
141

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