Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (12.7 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 656cf771 Christos Stavrakakis
    "cyclades.cpu",
50 41a7fae7 Christos Stavrakakis
    "cyclades.active_cpu",
51 656cf771 Christos Stavrakakis
    "cyclades.disk",
52 656cf771 Christos Stavrakakis
    "cyclades.ram",
53 41a7fae7 Christos Stavrakakis
    "cyclades.active_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 5db3a1e6 Christos Stavrakakis
    if strict:
168 5db3a1e6 Christos Stavrakakis
        failed = response["failed"]
169 5db3a1e6 Christos Stavrakakis
        if failed:
170 5db3a1e6 Christos Stavrakakis
            log.error("Unexpected error while resolving commissions: %s",
171 5db3a1e6 Christos Stavrakakis
                      failed)
172 5db3a1e6 Christos Stavrakakis
173 5db3a1e6 Christos Stavrakakis
    return response
174 11a54cb9 Christos Stavrakakis
175 11a54cb9 Christos Stavrakakis
176 2509ce17 Christos Stavrakakis
def fix_pending_commissions():
177 2509ce17 Christos Stavrakakis
    (accepted, rejected) = resolve_pending_commissions()
178 d195e752 Christos Stavrakakis
    resolve_commissions(accept=accepted, reject=rejected)
179 2509ce17 Christos Stavrakakis
180 2509ce17 Christos Stavrakakis
181 11a54cb9 Christos Stavrakakis
def resolve_pending_commissions():
182 11a54cb9 Christos Stavrakakis
    """Resolve quotaholder pending commissions.
183 11a54cb9 Christos Stavrakakis

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

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

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

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

345 5c8076b6 Christos Stavrakakis
    Create a new commission for a resource based on the action that
346 5c8076b6 Christos Stavrakakis
    is performed. If the resource has a previous pending commission,
347 5c8076b6 Christos Stavrakakis
    resolved it before issuing the new one.
348 5c8076b6 Christos Stavrakakis

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