Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / quotas / __init__.py @ 368d879e

History | View | Annotate | Download (12.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 629acc65 Giorgos Korfiatis
from astakosclient.errors import AstakosClientException, QuotaLimit
41 499d9bfe Christos Stavrakakis
from functools import wraps
42 bfe7ba3c Christos Stavrakakis
43 bfe7ba3c Christos Stavrakakis
import logging
44 bfe7ba3c Christos Stavrakakis
log = logging.getLogger(__name__)
45 bfe7ba3c Christos Stavrakakis
46 e407f159 Ilias Tsitsimpis
47 629acc65 Giorgos Korfiatis
DEFAULT_SOURCE = 'system'
48 656cf771 Christos Stavrakakis
RESOURCES = [
49 656cf771 Christos Stavrakakis
    "cyclades.vm",
50 656cf771 Christos Stavrakakis
    "cyclades.cpu",
51 41a7fae7 Christos Stavrakakis
    "cyclades.active_cpu",
52 656cf771 Christos Stavrakakis
    "cyclades.disk",
53 656cf771 Christos Stavrakakis
    "cyclades.ram",
54 41a7fae7 Christos Stavrakakis
    "cyclades.active_ram",
55 8b41683a Christos Stavrakakis
    "cyclades.network.private",
56 8b41683a Christos Stavrakakis
    "cyclades.floating_ip",
57 656cf771 Christos Stavrakakis
]
58 bfe7ba3c Christos Stavrakakis
59 bfe7ba3c Christos Stavrakakis
60 629acc65 Giorgos Korfiatis
class Quotaholder(object):
61 629acc65 Giorgos Korfiatis
    _object = None
62 629acc65 Giorgos Korfiatis
63 629acc65 Giorgos Korfiatis
    @classmethod
64 629acc65 Giorgos Korfiatis
    def get(cls):
65 629acc65 Giorgos Korfiatis
        if cls._object is None:
66 4fb643b3 Giorgos Korfiatis
            cls._object = AstakosClient(ASTAKOS_TOKEN,
67 4fb643b3 Giorgos Korfiatis
                                        ASTAKOS_AUTH_URL,
68 4fb643b3 Giorgos Korfiatis
                                        use_pool=True,
69 4fb643b3 Giorgos Korfiatis
                                        retry=3,
70 4fb643b3 Giorgos Korfiatis
                                        logger=log)
71 629acc65 Giorgos Korfiatis
        return cls._object
72 bfe7ba3c Christos Stavrakakis
73 bfe7ba3c Christos Stavrakakis
74 499d9bfe Christos Stavrakakis
def handle_astakosclient_error(func):
75 499d9bfe Christos Stavrakakis
    """Decorator for converting astakosclient errors to 500."""
76 499d9bfe Christos Stavrakakis
    @wraps(func)
77 499d9bfe Christos Stavrakakis
    def wrapper(*args, **kwargs):
78 499d9bfe Christos Stavrakakis
        try:
79 499d9bfe Christos Stavrakakis
            return func(*args, **kwargs)
80 499d9bfe Christos Stavrakakis
        except AstakosClientException:
81 499d9bfe Christos Stavrakakis
            log.exception("Unexpected error")
82 499d9bfe Christos Stavrakakis
            raise faults.InternalServerError("Unexpected error")
83 499d9bfe Christos Stavrakakis
    return wrapper
84 499d9bfe Christos Stavrakakis
85 499d9bfe Christos Stavrakakis
86 499d9bfe Christos Stavrakakis
@handle_astakosclient_error
87 16b959ce Giorgos Korfiatis
def issue_commission(resource, action, name="", force=False, auto_accept=False,
88 16b959ce Giorgos Korfiatis
                     action_fields=None):
89 bfe7ba3c Christos Stavrakakis
    """Issue a new commission to the quotaholder.
90 bfe7ba3c Christos Stavrakakis

91 bfe7ba3c Christos Stavrakakis
    Issue a new commission to the quotaholder, and create the
92 bfe7ba3c Christos Stavrakakis
    corresponing QuotaHolderSerial object in DB.
93 bfe7ba3c Christos Stavrakakis

94 bfe7ba3c Christos Stavrakakis
    """
95 bfe7ba3c Christos Stavrakakis
96 16b959ce Giorgos Korfiatis
    provisions = get_commission_info(resource=resource, action=action,
97 16b959ce Giorgos Korfiatis
                                     action_fields=action_fields)
98 16b959ce Giorgos Korfiatis
99 16b959ce Giorgos Korfiatis
    if provisions is None:
100 16b959ce Giorgos Korfiatis
        return None
101 16b959ce Giorgos Korfiatis
102 16b959ce Giorgos Korfiatis
    user = resource.userid
103 16b959ce Giorgos Korfiatis
    source = DEFAULT_SOURCE
104 16b959ce Giorgos Korfiatis
105 629acc65 Giorgos Korfiatis
    qh = Quotaholder.get()
106 629acc65 Giorgos Korfiatis
    try:
107 16b959ce Giorgos Korfiatis
        if True:  # placeholder
108 16b959ce Giorgos Korfiatis
            serial = qh.issue_one_commission(user, source,
109 16b959ce Giorgos Korfiatis
                                             provisions, name=name,
110 16b959ce Giorgos Korfiatis
                                             force=force,
111 16b959ce Giorgos Korfiatis
                                             auto_accept=auto_accept)
112 629acc65 Giorgos Korfiatis
    except QuotaLimit as e:
113 629acc65 Giorgos Korfiatis
        msg, details = render_overlimit_exception(e)
114 629acc65 Giorgos Korfiatis
        raise faults.OverLimit(msg, details=details)
115 bfe7ba3c Christos Stavrakakis
116 b14f55b5 Christos Stavrakakis
    if serial:
117 218de705 Christos Stavrakakis
        serial_info = {"serial": serial}
118 218de705 Christos Stavrakakis
        if auto_accept:
119 fb540e3a Giorgos Korfiatis
            serial_info["pending"] = False
120 218de705 Christos Stavrakakis
            serial_info["accept"] = True
121 218de705 Christos Stavrakakis
            serial_info["resolved"] = True
122 218de705 Christos Stavrakakis
        return QuotaHolderSerial.objects.create(**serial_info)
123 b14f55b5 Christos Stavrakakis
    else:
124 b14f55b5 Christos Stavrakakis
        raise Exception("No serial")
125 bfe7ba3c Christos Stavrakakis
126 bfe7ba3c Christos Stavrakakis
127 41a7fae7 Christos Stavrakakis
def accept_serial(serial, strict=True):
128 fb540e3a Giorgos Korfiatis
    assert serial.pending or serial.accept
129 41a7fae7 Christos Stavrakakis
    response = resolve_commissions(accept=[serial.serial], strict=strict)
130 fb540e3a Giorgos Korfiatis
    serial.pending = False
131 41a7fae7 Christos Stavrakakis
    serial.accept = True
132 41a7fae7 Christos Stavrakakis
    serial.resolved = True
133 41a7fae7 Christos Stavrakakis
    serial.save()
134 41a7fae7 Christos Stavrakakis
    return response
135 41a7fae7 Christos Stavrakakis
136 41a7fae7 Christos Stavrakakis
137 41a7fae7 Christos Stavrakakis
def reject_serial(serial, strict=True):
138 fb540e3a Giorgos Korfiatis
    assert serial.pending or not serial.accept
139 41a7fae7 Christos Stavrakakis
    response = resolve_commissions(reject=[serial.serial], strict=strict)
140 fb540e3a Giorgos Korfiatis
    serial.pending = False
141 fb540e3a Giorgos Korfiatis
    serial.accept = False
142 41a7fae7 Christos Stavrakakis
    serial.resolved = True
143 41a7fae7 Christos Stavrakakis
    serial.save()
144 41a7fae7 Christos Stavrakakis
    return response
145 41a7fae7 Christos Stavrakakis
146 41a7fae7 Christos Stavrakakis
147 5db3a1e6 Christos Stavrakakis
def accept_commissions(accepted, strict=True):
148 d195e752 Christos Stavrakakis
    return resolve_commissions(accept=accepted, strict=strict)
149 11a54cb9 Christos Stavrakakis
150 11a54cb9 Christos Stavrakakis
151 5db3a1e6 Christos Stavrakakis
def reject_commissions(rejected, strict=True):
152 d195e752 Christos Stavrakakis
    return resolve_commissions(reject=rejected, strict=strict)
153 11a54cb9 Christos Stavrakakis
154 11a54cb9 Christos Stavrakakis
155 499d9bfe Christos Stavrakakis
@handle_astakosclient_error
156 d195e752 Christos Stavrakakis
def resolve_commissions(accept=None, reject=None, strict=True):
157 629acc65 Giorgos Korfiatis
    if accept is None:
158 629acc65 Giorgos Korfiatis
        accept = []
159 629acc65 Giorgos Korfiatis
    if reject is None:
160 629acc65 Giorgos Korfiatis
        reject = []
161 11a54cb9 Christos Stavrakakis
162 629acc65 Giorgos Korfiatis
    qh = Quotaholder.get()
163 e407f159 Ilias Tsitsimpis
    response = qh.resolve_commissions(accept, reject)
164 5db3a1e6 Christos Stavrakakis
165 5db3a1e6 Christos Stavrakakis
    if strict:
166 5db3a1e6 Christos Stavrakakis
        failed = response["failed"]
167 5db3a1e6 Christos Stavrakakis
        if failed:
168 5db3a1e6 Christos Stavrakakis
            log.error("Unexpected error while resolving commissions: %s",
169 5db3a1e6 Christos Stavrakakis
                      failed)
170 5db3a1e6 Christos Stavrakakis
171 5db3a1e6 Christos Stavrakakis
    return response
172 11a54cb9 Christos Stavrakakis
173 11a54cb9 Christos Stavrakakis
174 2509ce17 Christos Stavrakakis
def fix_pending_commissions():
175 2509ce17 Christos Stavrakakis
    (accepted, rejected) = resolve_pending_commissions()
176 d195e752 Christos Stavrakakis
    resolve_commissions(accept=accepted, reject=rejected)
177 2509ce17 Christos Stavrakakis
178 2509ce17 Christos Stavrakakis
179 11a54cb9 Christos Stavrakakis
def resolve_pending_commissions():
180 11a54cb9 Christos Stavrakakis
    """Resolve quotaholder pending commissions.
181 11a54cb9 Christos Stavrakakis

182 11a54cb9 Christos Stavrakakis
    Get pending commissions from the quotaholder and resolve them
183 11a54cb9 Christos Stavrakakis
    to accepted and rejected, according to the state of the
184 11a54cb9 Christos Stavrakakis
    QuotaHolderSerial DB table. A pending commission in the quotaholder
185 11a54cb9 Christos Stavrakakis
    can exist in the QuotaHolderSerial table and be either accepted or
186 8d5795b4 Christos Stavrakakis
    rejected, or cannot exist in this table, so it is rejected.
187 11a54cb9 Christos Stavrakakis

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

243 2509ce17 Christos Stavrakakis
    This function implements the Commission workflow, and must be called
244 2509ce17 Christos Stavrakakis
    exactly after and in the same transaction that created/updated the
245 2509ce17 Christos Stavrakakis
    resource. The workflow that implements is the following:
246 4ed25171 Christos Stavrakakis
    0) Resolve previous unresolved commission if exists
247 21eb7404 Christos Stavrakakis
    1) Issue commission, get a serial and correlate it with the resource
248 21eb7404 Christos Stavrakakis
    2) Store the serial in DB as a serial to accept
249 21eb7404 Christos Stavrakakis
    3) COMMIT!
250 21eb7404 Christos Stavrakakis
    4) Accept commission to QH
251 2509ce17 Christos Stavrakakis

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

340 5c8076b6 Christos Stavrakakis
    Create a new commission for a resource based on the action that
341 5c8076b6 Christos Stavrakakis
    is performed. If the resource has a previous pending commission,
342 5c8076b6 Christos Stavrakakis
    resolved it before issuing the new one.
343 5c8076b6 Christos Stavrakakis

344 5c8076b6 Christos Stavrakakis
    """
345 5c8076b6 Christos Stavrakakis
    # Try to resolve previous serial
346 fb540e3a Giorgos Korfiatis
    resolve_commission(resource.serial, force=force)
347 5c8076b6 Christos Stavrakakis
348 16b959ce Giorgos Korfiatis
    serial = issue_commission(resource, action, name=commission_name,
349 16b959ce Giorgos Korfiatis
                              force=force, auto_accept=auto_accept,
350 16b959ce Giorgos Korfiatis
                              action_fields=action_fields)
351 5c8076b6 Christos Stavrakakis
    resource.serial = serial
352 16b959ce Giorgos Korfiatis
    resource.save()
353 21eb7404 Christos Stavrakakis
    return serial
354 5c8076b6 Christos Stavrakakis
355 5c8076b6 Christos Stavrakakis
356 fb540e3a Giorgos Korfiatis
class ResolveError(Exception):
357 fb540e3a Giorgos Korfiatis
    pass
358 fb540e3a Giorgos Korfiatis
359 fb540e3a Giorgos Korfiatis
360 fb540e3a Giorgos Korfiatis
def resolve_commission(serial, force=False):
361 5c8076b6 Christos Stavrakakis
    if serial is None or serial.resolved:
362 5c8076b6 Christos Stavrakakis
        return
363 fb540e3a Giorgos Korfiatis
    if serial.pending and not force:
364 fb540e3a Giorgos Korfiatis
        m = "Could not resolve commission: serial %s is undecided" % serial
365 fb540e3a Giorgos Korfiatis
        raise ResolveError(m)
366 41a7fae7 Christos Stavrakakis
    log.warning("Resolving pending commission: %s", serial)
367 41a7fae7 Christos Stavrakakis
    if not serial.pending and serial.accept:
368 41a7fae7 Christos Stavrakakis
        accept_serial(serial)
369 41a7fae7 Christos Stavrakakis
    else:
370 41a7fae7 Christos Stavrakakis
        reject_serial(serial)