Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / quotas / __init__.py @ 19b2c29d

History | View | Annotate | Download (13.5 kB)

1 629acc65 Giorgos Korfiatis
# Copyright 2012, 2013 GRNET S.A. All rights reserved.
2 bfe7ba3c Christos Stavrakakis
#
3 bfe7ba3c Christos Stavrakakis
# Redistribution and use in source and binary forms, with or without
4 bfe7ba3c Christos Stavrakakis
# modification, are permitted provided that the following conditions
5 bfe7ba3c Christos Stavrakakis
# are met:
6 bfe7ba3c Christos Stavrakakis
#
7 bfe7ba3c Christos Stavrakakis
#   1. Redistributions of source code must retain the above copyright
8 bfe7ba3c Christos Stavrakakis
#      notice, this list of conditions and the following disclaimer.
9 bfe7ba3c Christos Stavrakakis
#
10 bfe7ba3c Christos Stavrakakis
#  2. Redistributions in binary form must reproduce the above copyright
11 bfe7ba3c Christos Stavrakakis
#     notice, this list of conditions and the following disclaimer in the
12 bfe7ba3c Christos Stavrakakis
#     documentation and/or other materials provided with the distribution.
13 bfe7ba3c Christos Stavrakakis
#
14 bfe7ba3c Christos Stavrakakis
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
15 bfe7ba3c Christos Stavrakakis
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 bfe7ba3c Christos Stavrakakis
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 bfe7ba3c Christos Stavrakakis
# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
18 bfe7ba3c Christos Stavrakakis
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 bfe7ba3c Christos Stavrakakis
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 bfe7ba3c Christos Stavrakakis
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 bfe7ba3c Christos Stavrakakis
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 bfe7ba3c Christos Stavrakakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 bfe7ba3c Christos Stavrakakis
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 bfe7ba3c Christos Stavrakakis
# SUCH DAMAGE.
25 bfe7ba3c Christos Stavrakakis
#
26 bfe7ba3c Christos Stavrakakis
# The views and conclusions contained in the software and documentation are
27 bfe7ba3c Christos Stavrakakis
# those of the authors and should not be interpreted as representing official
28 bfe7ba3c Christos Stavrakakis
# policies, either expressed or implied, of GRNET S.A.
29 bfe7ba3c Christos Stavrakakis
30 656cf771 Christos Stavrakakis
from django.utils import simplejson as json
31 2509ce17 Christos Stavrakakis
from django.db import transaction
32 bfe7ba3c Christos Stavrakakis
33 bd40abfa Christos Stavrakakis
from snf_django.lib.api import faults
34 8b41683a Christos Stavrakakis
from synnefo.db.models import (QuotaHolderSerial, VirtualMachine, Network,
35 326c3ec8 Christos Stavrakakis
                               IPAddress)
36 6dbd90c0 Christos Stavrakakis
37 18c4414d Giorgos Korfiatis
from synnefo.settings import (CYCLADES_SERVICE_TOKEN as ASTAKOS_TOKEN,
38 e407f159 Ilias Tsitsimpis
                              ASTAKOS_AUTH_URL)
39 629acc65 Giorgos Korfiatis
from astakosclient import AstakosClient
40 0dc4b304 Giorgos Korfiatis
from astakosclient import errors
41 bfe7ba3c Christos Stavrakakis
42 bfe7ba3c Christos Stavrakakis
import logging
43 bfe7ba3c Christos Stavrakakis
log = logging.getLogger(__name__)
44 bfe7ba3c Christos Stavrakakis
45 e407f159 Ilias Tsitsimpis
46 629acc65 Giorgos Korfiatis
DEFAULT_SOURCE = 'system'
47 656cf771 Christos Stavrakakis
RESOURCES = [
48 656cf771 Christos Stavrakakis
    "cyclades.vm",
49 5083fc47 Christos Stavrakakis
    "cyclades.total_cpu",
50 656cf771 Christos Stavrakakis
    "cyclades.cpu",
51 656cf771 Christos Stavrakakis
    "cyclades.disk",
52 5083fc47 Christos Stavrakakis
    "cyclades.total_ram",
53 656cf771 Christos Stavrakakis
    "cyclades.ram",
54 8b41683a Christos Stavrakakis
    "cyclades.network.private",
55 8b41683a Christos Stavrakakis
    "cyclades.floating_ip",
56 656cf771 Christos Stavrakakis
]
57 bfe7ba3c Christos Stavrakakis
58 bfe7ba3c Christos Stavrakakis
59 629acc65 Giorgos Korfiatis
class Quotaholder(object):
60 629acc65 Giorgos Korfiatis
    _object = None
61 629acc65 Giorgos Korfiatis
62 629acc65 Giorgos Korfiatis
    @classmethod
63 629acc65 Giorgos Korfiatis
    def get(cls):
64 629acc65 Giorgos Korfiatis
        if cls._object is None:
65 4fb643b3 Giorgos Korfiatis
            cls._object = AstakosClient(ASTAKOS_TOKEN,
66 4fb643b3 Giorgos Korfiatis
                                        ASTAKOS_AUTH_URL,
67 4fb643b3 Giorgos Korfiatis
                                        use_pool=True,
68 4fb643b3 Giorgos Korfiatis
                                        retry=3,
69 4fb643b3 Giorgos Korfiatis
                                        logger=log)
70 629acc65 Giorgos Korfiatis
        return cls._object
71 bfe7ba3c Christos Stavrakakis
72 bfe7ba3c Christos Stavrakakis
73 0dc4b304 Giorgos Korfiatis
class AstakosClientExceptionHandler(object):
74 0dc4b304 Giorgos Korfiatis
    def __init__(self, *args, **kwargs):
75 0dc4b304 Giorgos Korfiatis
        pass
76 0dc4b304 Giorgos Korfiatis
77 0dc4b304 Giorgos Korfiatis
    def __enter__(self):
78 0dc4b304 Giorgos Korfiatis
        pass
79 0dc4b304 Giorgos Korfiatis
80 0dc4b304 Giorgos Korfiatis
    def __exit__(self, exc_type, value, traceback):
81 0dc4b304 Giorgos Korfiatis
        if value is not None:  # exception
82 0dc4b304 Giorgos Korfiatis
            if not isinstance(value, errors.AstakosClientException):
83 0dc4b304 Giorgos Korfiatis
                return False  # reraise
84 0dc4b304 Giorgos Korfiatis
            if exc_type is errors.QuotaLimit:
85 0dc4b304 Giorgos Korfiatis
                msg, details = render_overlimit_exception(value)
86 0dc4b304 Giorgos Korfiatis
                raise faults.OverLimit(msg, details=details)
87 0dc4b304 Giorgos Korfiatis
88 0dc4b304 Giorgos Korfiatis
            log.exception("Unexpected error %s" % value.message)
89 499d9bfe Christos Stavrakakis
            raise faults.InternalServerError("Unexpected error")
90 499d9bfe Christos Stavrakakis
91 499d9bfe Christos Stavrakakis
92 16b959ce Giorgos Korfiatis
def issue_commission(resource, action, name="", force=False, auto_accept=False,
93 16b959ce Giorgos Korfiatis
                     action_fields=None):
94 bfe7ba3c Christos Stavrakakis
    """Issue a new commission to the quotaholder.
95 bfe7ba3c Christos Stavrakakis

96 bfe7ba3c Christos Stavrakakis
    Issue a new commission to the quotaholder, and create the
97 bfe7ba3c Christos Stavrakakis
    corresponing QuotaHolderSerial object in DB.
98 bfe7ba3c Christos Stavrakakis

99 bfe7ba3c Christos Stavrakakis
    """
100 bfe7ba3c Christos Stavrakakis
101 16b959ce Giorgos Korfiatis
    provisions = get_commission_info(resource=resource, action=action,
102 16b959ce Giorgos Korfiatis
                                     action_fields=action_fields)
103 16b959ce Giorgos Korfiatis
104 16b959ce Giorgos Korfiatis
    if provisions is None:
105 16b959ce Giorgos Korfiatis
        return None
106 16b959ce Giorgos Korfiatis
107 16b959ce Giorgos Korfiatis
    user = resource.userid
108 16b959ce Giorgos Korfiatis
    source = DEFAULT_SOURCE
109 16b959ce Giorgos Korfiatis
110 629acc65 Giorgos Korfiatis
    qh = Quotaholder.get()
111 0dc4b304 Giorgos Korfiatis
    if True:  # placeholder
112 0dc4b304 Giorgos Korfiatis
        with AstakosClientExceptionHandler():
113 16b959ce Giorgos Korfiatis
            serial = qh.issue_one_commission(user, source,
114 16b959ce Giorgos Korfiatis
                                             provisions, name=name,
115 16b959ce Giorgos Korfiatis
                                             force=force,
116 16b959ce Giorgos Korfiatis
                                             auto_accept=auto_accept)
117 bfe7ba3c Christos Stavrakakis
118 b14f55b5 Christos Stavrakakis
    if serial:
119 218de705 Christos Stavrakakis
        serial_info = {"serial": serial}
120 218de705 Christos Stavrakakis
        if auto_accept:
121 fb540e3a Giorgos Korfiatis
            serial_info["pending"] = False
122 218de705 Christos Stavrakakis
            serial_info["accept"] = True
123 218de705 Christos Stavrakakis
            serial_info["resolved"] = True
124 218de705 Christos Stavrakakis
        return QuotaHolderSerial.objects.create(**serial_info)
125 b14f55b5 Christos Stavrakakis
    else:
126 b14f55b5 Christos Stavrakakis
        raise Exception("No serial")
127 bfe7ba3c Christos Stavrakakis
128 bfe7ba3c Christos Stavrakakis
129 41a7fae7 Christos Stavrakakis
def accept_serial(serial, strict=True):
130 fb540e3a Giorgos Korfiatis
    assert serial.pending or serial.accept
131 41a7fae7 Christos Stavrakakis
    response = resolve_commissions(accept=[serial.serial], strict=strict)
132 fb540e3a Giorgos Korfiatis
    serial.pending = False
133 41a7fae7 Christos Stavrakakis
    serial.accept = True
134 41a7fae7 Christos Stavrakakis
    serial.resolved = True
135 41a7fae7 Christos Stavrakakis
    serial.save()
136 41a7fae7 Christos Stavrakakis
    return response
137 41a7fae7 Christos Stavrakakis
138 41a7fae7 Christos Stavrakakis
139 41a7fae7 Christos Stavrakakis
def reject_serial(serial, strict=True):
140 fb540e3a Giorgos Korfiatis
    assert serial.pending or not serial.accept
141 41a7fae7 Christos Stavrakakis
    response = resolve_commissions(reject=[serial.serial], strict=strict)
142 fb540e3a Giorgos Korfiatis
    serial.pending = False
143 fb540e3a Giorgos Korfiatis
    serial.accept = False
144 41a7fae7 Christos Stavrakakis
    serial.resolved = True
145 41a7fae7 Christos Stavrakakis
    serial.save()
146 41a7fae7 Christos Stavrakakis
    return response
147 41a7fae7 Christos Stavrakakis
148 41a7fae7 Christos Stavrakakis
149 5db3a1e6 Christos Stavrakakis
def accept_commissions(accepted, strict=True):
150 d195e752 Christos Stavrakakis
    return resolve_commissions(accept=accepted, strict=strict)
151 11a54cb9 Christos Stavrakakis
152 11a54cb9 Christos Stavrakakis
153 5db3a1e6 Christos Stavrakakis
def reject_commissions(rejected, strict=True):
154 d195e752 Christos Stavrakakis
    return resolve_commissions(reject=rejected, strict=strict)
155 11a54cb9 Christos Stavrakakis
156 11a54cb9 Christos Stavrakakis
157 d195e752 Christos Stavrakakis
def resolve_commissions(accept=None, reject=None, strict=True):
158 629acc65 Giorgos Korfiatis
    if accept is None:
159 629acc65 Giorgos Korfiatis
        accept = []
160 629acc65 Giorgos Korfiatis
    if reject is None:
161 629acc65 Giorgos Korfiatis
        reject = []
162 11a54cb9 Christos Stavrakakis
163 629acc65 Giorgos Korfiatis
    qh = Quotaholder.get()
164 0dc4b304 Giorgos Korfiatis
    with AstakosClientExceptionHandler():
165 0dc4b304 Giorgos Korfiatis
        response = qh.resolve_commissions(accept, reject)
166 5db3a1e6 Christos Stavrakakis
167 3af1fb4b Christos Stavrakakis
    # Update correspodning entries in DB
168 3af1fb4b Christos Stavrakakis
    QuotaHolderSerial.objects.filter(serial__in=accept).update(accept=True,
169 3af1fb4b Christos Stavrakakis
                                                               pending=False,
170 3af1fb4b Christos Stavrakakis
                                                               resolved=True)
171 3af1fb4b Christos Stavrakakis
    QuotaHolderSerial.objects.filter(serial__in=reject).update(accept=False,
172 3af1fb4b Christos Stavrakakis
                                                               pending=False,
173 3af1fb4b Christos Stavrakakis
                                                               resolved=True)
174 3af1fb4b Christos Stavrakakis
175 5db3a1e6 Christos Stavrakakis
    if strict:
176 5db3a1e6 Christos Stavrakakis
        failed = response["failed"]
177 5db3a1e6 Christos Stavrakakis
        if failed:
178 5db3a1e6 Christos Stavrakakis
            log.error("Unexpected error while resolving commissions: %s",
179 5db3a1e6 Christos Stavrakakis
                      failed)
180 5db3a1e6 Christos Stavrakakis
181 5db3a1e6 Christos Stavrakakis
    return response
182 11a54cb9 Christos Stavrakakis
183 11a54cb9 Christos Stavrakakis
184 2509ce17 Christos Stavrakakis
def fix_pending_commissions():
185 2509ce17 Christos Stavrakakis
    (accepted, rejected) = resolve_pending_commissions()
186 d195e752 Christos Stavrakakis
    resolve_commissions(accept=accepted, reject=rejected)
187 2509ce17 Christos Stavrakakis
188 2509ce17 Christos Stavrakakis
189 11a54cb9 Christos Stavrakakis
def resolve_pending_commissions():
190 11a54cb9 Christos Stavrakakis
    """Resolve quotaholder pending commissions.
191 11a54cb9 Christos Stavrakakis

192 11a54cb9 Christos Stavrakakis
    Get pending commissions from the quotaholder and resolve them
193 11a54cb9 Christos Stavrakakis
    to accepted and rejected, according to the state of the
194 11a54cb9 Christos Stavrakakis
    QuotaHolderSerial DB table. A pending commission in the quotaholder
195 11a54cb9 Christos Stavrakakis
    can exist in the QuotaHolderSerial table and be either accepted or
196 8d5795b4 Christos Stavrakakis
    rejected, or cannot exist in this table, so it is rejected.
197 11a54cb9 Christos Stavrakakis

198 11a54cb9 Christos Stavrakakis
    """
199 11a54cb9 Christos Stavrakakis
200 11a54cb9 Christos Stavrakakis
    qh_pending = get_quotaholder_pending()
201 11a54cb9 Christos Stavrakakis
    if not qh_pending:
202 11a54cb9 Christos Stavrakakis
        return ([], [])
203 11a54cb9 Christos Stavrakakis
204 11a54cb9 Christos Stavrakakis
    qh_pending.sort()
205 11a54cb9 Christos Stavrakakis
    min_ = qh_pending[0]
206 11a54cb9 Christos Stavrakakis
207 11a54cb9 Christos Stavrakakis
    serials = QuotaHolderSerial.objects.filter(serial__gte=min_, pending=False)
208 2509ce17 Christos Stavrakakis
    accepted = serials.filter(accept=True).values_list('serial', flat=True)
209 11a54cb9 Christos Stavrakakis
    accepted = filter(lambda x: x in qh_pending, accepted)
210 11a54cb9 Christos Stavrakakis
211 11a54cb9 Christos Stavrakakis
    rejected = list(set(qh_pending) - set(accepted))
212 11a54cb9 Christos Stavrakakis
213 11a54cb9 Christos Stavrakakis
    return (accepted, rejected)
214 11a54cb9 Christos Stavrakakis
215 11a54cb9 Christos Stavrakakis
216 11a54cb9 Christos Stavrakakis
def get_quotaholder_pending():
217 629acc65 Giorgos Korfiatis
    qh = Quotaholder.get()
218 e407f159 Ilias Tsitsimpis
    pending_serials = qh.get_pending_commissions()
219 11a54cb9 Christos Stavrakakis
    return pending_serials
220 5a70b1a3 Christos Stavrakakis
221 5a70b1a3 Christos Stavrakakis
222 629acc65 Giorgos Korfiatis
def render_overlimit_exception(e):
223 5a70b1a3 Christos Stavrakakis
    resource_name = {"vm": "Virtual Machine",
224 5a70b1a3 Christos Stavrakakis
                     "cpu": "CPU",
225 5a70b1a3 Christos Stavrakakis
                     "ram": "RAM",
226 8b41683a Christos Stavrakakis
                     "network.private": "Private Network",
227 8b41683a Christos Stavrakakis
                     "floating_ip": "Floating IP address"}
228 656cf771 Christos Stavrakakis
    details = json.loads(e.details)
229 629acc65 Giorgos Korfiatis
    data = details['overLimit']['data']
230 656cf771 Christos Stavrakakis
    usage = data["usage"]
231 656cf771 Christos Stavrakakis
    limit = data["limit"]
232 656cf771 Christos Stavrakakis
    available = limit - usage
233 629acc65 Giorgos Korfiatis
    provision = data['provision']
234 629acc65 Giorgos Korfiatis
    requested = provision['quantity']
235 629acc65 Giorgos Korfiatis
    resource = provision['resource']
236 629acc65 Giorgos Korfiatis
    res = resource.replace("cyclades.", "", 1)
237 5a70b1a3 Christos Stavrakakis
    try:
238 5a70b1a3 Christos Stavrakakis
        resource = resource_name[res]
239 5a70b1a3 Christos Stavrakakis
    except KeyError:
240 5a70b1a3 Christos Stavrakakis
        resource = res
241 5a70b1a3 Christos Stavrakakis
242 5a70b1a3 Christos Stavrakakis
    msg = "Resource Limit Exceeded for your account."
243 5a70b1a3 Christos Stavrakakis
    details = "Limit for resource '%s' exceeded for your account."\
244 629acc65 Giorgos Korfiatis
              " Available: %s, Requested: %s"\
245 629acc65 Giorgos Korfiatis
              % (resource, available, requested)
246 5a70b1a3 Christos Stavrakakis
    return msg, details
247 2509ce17 Christos Stavrakakis
248 2509ce17 Christos Stavrakakis
249 21eb7404 Christos Stavrakakis
@transaction.commit_on_success
250 368d879e Giorgos Korfiatis
def issue_and_accept_commission(resource, action="BUILD", action_fields=None):
251 2509ce17 Christos Stavrakakis
    """Issue and accept a commission to Quotaholder.
252 2509ce17 Christos Stavrakakis

253 2509ce17 Christos Stavrakakis
    This function implements the Commission workflow, and must be called
254 2509ce17 Christos Stavrakakis
    exactly after and in the same transaction that created/updated the
255 2509ce17 Christos Stavrakakis
    resource. The workflow that implements is the following:
256 4ed25171 Christos Stavrakakis
    0) Resolve previous unresolved commission if exists
257 21eb7404 Christos Stavrakakis
    1) Issue commission, get a serial and correlate it with the resource
258 21eb7404 Christos Stavrakakis
    2) Store the serial in DB as a serial to accept
259 21eb7404 Christos Stavrakakis
    3) COMMIT!
260 21eb7404 Christos Stavrakakis
    4) Accept commission to QH
261 2509ce17 Christos Stavrakakis

262 2509ce17 Christos Stavrakakis
    """
263 368d879e Giorgos Korfiatis
    commission_reason = ("client: api, resource: %s, action: %s"
264 368d879e Giorgos Korfiatis
                         % (resource, action))
265 21eb7404 Christos Stavrakakis
    serial = handle_resource_commission(resource=resource, action=action,
266 368d879e Giorgos Korfiatis
                                        action_fields=action_fields,
267 21eb7404 Christos Stavrakakis
                                        commission_name=commission_reason)
268 4ed25171 Christos Stavrakakis
269 21eb7404 Christos Stavrakakis
    # Mark the serial as one to accept and associate it with the resource
270 21eb7404 Christos Stavrakakis
    serial.pending = False
271 21eb7404 Christos Stavrakakis
    serial.accept = True
272 21eb7404 Christos Stavrakakis
    serial.save()
273 21eb7404 Christos Stavrakakis
    transaction.commit()
274 2509ce17 Christos Stavrakakis
275 2509ce17 Christos Stavrakakis
    try:
276 41a7fae7 Christos Stavrakakis
        # Accept the commission to quotaholder
277 41a7fae7 Christos Stavrakakis
        accept_serial(serial)
278 2509ce17 Christos Stavrakakis
    except:
279 21eb7404 Christos Stavrakakis
        # Do not crash if we can not accept commission to Quotaholder. Quotas
280 21eb7404 Christos Stavrakakis
        # have already been reserved and the resource already exists in DB.
281 21eb7404 Christos Stavrakakis
        # Just log the error
282 21eb7404 Christos Stavrakakis
        log.exception("Failed to accept commission: %s", serial)
283 21eb7404 Christos Stavrakakis
284 21eb7404 Christos Stavrakakis
    return serial
285 2509ce17 Christos Stavrakakis
286 2509ce17 Christos Stavrakakis
287 41a7fae7 Christos Stavrakakis
def get_commission_info(resource, action, action_fields=None):
288 41a7fae7 Christos Stavrakakis
    if isinstance(resource, VirtualMachine):
289 41a7fae7 Christos Stavrakakis
        flavor = resource.flavor
290 41a7fae7 Christos Stavrakakis
        resources = {"cyclades.vm": 1,
291 5083fc47 Christos Stavrakakis
                     "cyclades.total_cpu": flavor.cpu,
292 41a7fae7 Christos Stavrakakis
                     "cyclades.disk": 1073741824 * flavor.disk,
293 5083fc47 Christos Stavrakakis
                     "cyclades.total_ram": 1048576 * flavor.ram}
294 5083fc47 Christos Stavrakakis
        online_resources = {"cyclades.cpu": flavor.cpu,
295 5083fc47 Christos Stavrakakis
                            "cyclades.ram": 1048576 * flavor.ram}
296 bb649089 Christos Stavrakakis
        if action == "BUILD":
297 bb649089 Christos Stavrakakis
            resources.update(online_resources)
298 bb649089 Christos Stavrakakis
            return resources
299 41a7fae7 Christos Stavrakakis
        if action == "START":
300 41a7fae7 Christos Stavrakakis
            if resource.operstate == "STOPPED":
301 41a7fae7 Christos Stavrakakis
                return online_resources
302 41a7fae7 Christos Stavrakakis
            else:
303 41a7fae7 Christos Stavrakakis
                return None
304 41a7fae7 Christos Stavrakakis
        elif action == "STOP":
305 41a7fae7 Christos Stavrakakis
            if resource.operstate in ["STARTED", "BUILD", "ERROR"]:
306 41a7fae7 Christos Stavrakakis
                return reverse_quantities(online_resources)
307 41a7fae7 Christos Stavrakakis
            else:
308 41a7fae7 Christos Stavrakakis
                return None
309 41a7fae7 Christos Stavrakakis
        elif action == "REBOOT":
310 41a7fae7 Christos Stavrakakis
            if resource.operstate == "STOPPED":
311 41a7fae7 Christos Stavrakakis
                return online_resources
312 41a7fae7 Christos Stavrakakis
            else:
313 41a7fae7 Christos Stavrakakis
                return None
314 41a7fae7 Christos Stavrakakis
        elif action == "DESTROY":
315 41a7fae7 Christos Stavrakakis
            if resource.operstate in ["STARTED", "BUILD", "ERROR"]:
316 41a7fae7 Christos Stavrakakis
                resources.update(online_resources)
317 41a7fae7 Christos Stavrakakis
            return reverse_quantities(resources)
318 41a7fae7 Christos Stavrakakis
        elif action == "RESIZE" and action_fields:
319 41a7fae7 Christos Stavrakakis
            beparams = action_fields.get("beparams")
320 41a7fae7 Christos Stavrakakis
            cpu = beparams.get("vcpus", flavor.cpu)
321 41a7fae7 Christos Stavrakakis
            ram = beparams.get("maxmem", flavor.ram)
322 5083fc47 Christos Stavrakakis
            return {"cyclades.total_cpu": cpu - flavor.cpu,
323 5083fc47 Christos Stavrakakis
                    "cyclades.total_ram": 1048576 * (ram - flavor.ram)}
324 41a7fae7 Christos Stavrakakis
        else:
325 41a7fae7 Christos Stavrakakis
            #["CONNECT", "DISCONNECT", "SET_FIREWALL_PROFILE"]:
326 41a7fae7 Christos Stavrakakis
            return None
327 16b959ce Giorgos Korfiatis
    elif isinstance(resource, Network):
328 16b959ce Giorgos Korfiatis
        resources = {"cyclades.network.private": 1}
329 16b959ce Giorgos Korfiatis
        if action == "BUILD":
330 16b959ce Giorgos Korfiatis
            return resources
331 16b959ce Giorgos Korfiatis
        elif action == "DESTROY":
332 16b959ce Giorgos Korfiatis
            return reverse_quantities(resources)
333 44183264 Christos Stavrakakis
    elif isinstance(resource, IPAddress):
334 44183264 Christos Stavrakakis
        if resource.floating_ip:
335 44183264 Christos Stavrakakis
            resources = {"cyclades.floating_ip": 1}
336 44183264 Christos Stavrakakis
            if action == "BUILD":
337 44183264 Christos Stavrakakis
                return resources
338 44183264 Christos Stavrakakis
            elif action == "DESTROY":
339 44183264 Christos Stavrakakis
                return reverse_quantities(resources)
340 44183264 Christos Stavrakakis
        else:
341 44183264 Christos Stavrakakis
            return None
342 41a7fae7 Christos Stavrakakis
343 41a7fae7 Christos Stavrakakis
344 2509ce17 Christos Stavrakakis
def reverse_quantities(resources):
345 2509ce17 Christos Stavrakakis
    return dict((r, -s) for r, s in resources.items())
346 41a7fae7 Christos Stavrakakis
347 41a7fae7 Christos Stavrakakis
348 5c8076b6 Christos Stavrakakis
def handle_resource_commission(resource, action, commission_name,
349 16b959ce Giorgos Korfiatis
                               force=False, auto_accept=False,
350 16b959ce Giorgos Korfiatis
                               action_fields=None):
351 5c8076b6 Christos Stavrakakis
    """Handle a issuing of a commission for a resource.
352 5c8076b6 Christos Stavrakakis

353 5c8076b6 Christos Stavrakakis
    Create a new commission for a resource based on the action that
354 5c8076b6 Christos Stavrakakis
    is performed. If the resource has a previous pending commission,
355 5c8076b6 Christos Stavrakakis
    resolved it before issuing the new one.
356 5c8076b6 Christos Stavrakakis

357 5c8076b6 Christos Stavrakakis
    """
358 1fdd8d69 Christos Stavrakakis
    # Try to resolve previous serial:
359 1fdd8d69 Christos Stavrakakis
    # If action is DESTROY, we must always reject the previous commission,
360 1fdd8d69 Christos Stavrakakis
    # since multiple DESTROY actions are allowed in the same resource (e.g. VM)
361 1fdd8d69 Christos Stavrakakis
    # The one who succeeds will be finally accepted, and all other will be
362 1fdd8d69 Christos Stavrakakis
    # rejected
363 1fdd8d69 Christos Stavrakakis
    force = force or (action == "DESTROY")
364 fb540e3a Giorgos Korfiatis
    resolve_commission(resource.serial, force=force)
365 5c8076b6 Christos Stavrakakis
366 16b959ce Giorgos Korfiatis
    serial = issue_commission(resource, action, name=commission_name,
367 16b959ce Giorgos Korfiatis
                              force=force, auto_accept=auto_accept,
368 16b959ce Giorgos Korfiatis
                              action_fields=action_fields)
369 5c8076b6 Christos Stavrakakis
    resource.serial = serial
370 16b959ce Giorgos Korfiatis
    resource.save()
371 21eb7404 Christos Stavrakakis
    return serial
372 5c8076b6 Christos Stavrakakis
373 5c8076b6 Christos Stavrakakis
374 fb540e3a Giorgos Korfiatis
class ResolveError(Exception):
375 fb540e3a Giorgos Korfiatis
    pass
376 fb540e3a Giorgos Korfiatis
377 fb540e3a Giorgos Korfiatis
378 fb540e3a Giorgos Korfiatis
def resolve_commission(serial, force=False):
379 5c8076b6 Christos Stavrakakis
    if serial is None or serial.resolved:
380 5c8076b6 Christos Stavrakakis
        return
381 fb540e3a Giorgos Korfiatis
    if serial.pending and not force:
382 fb540e3a Giorgos Korfiatis
        m = "Could not resolve commission: serial %s is undecided" % serial
383 fb540e3a Giorgos Korfiatis
        raise ResolveError(m)
384 41a7fae7 Christos Stavrakakis
    log.warning("Resolving pending commission: %s", serial)
385 41a7fae7 Christos Stavrakakis
    if not serial.pending and serial.accept:
386 41a7fae7 Christos Stavrakakis
        accept_serial(serial)
387 41a7fae7 Christos Stavrakakis
    else:
388 41a7fae7 Christos Stavrakakis
        reject_serial(serial)