Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (13.4 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 e3ff6830 Georgios D. Tsoukalas
                              ASTAKOS_BASE_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 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 629acc65 Giorgos Korfiatis
            cls._object = AstakosClient(
66 e3ff6830 Georgios D. Tsoukalas
                ASTAKOS_BASE_URL,
67 629acc65 Giorgos Korfiatis
                use_pool=True,
68 d1d7ec34 Christos Stavrakakis
                retry=3,
69 629acc65 Giorgos Korfiatis
                logger=log)
70 629acc65 Giorgos Korfiatis
        return cls._object
71 bfe7ba3c Christos Stavrakakis
72 bfe7ba3c Christos Stavrakakis
73 499d9bfe Christos Stavrakakis
def handle_astakosclient_error(func):
74 499d9bfe Christos Stavrakakis
    """Decorator for converting astakosclient errors to 500."""
75 499d9bfe Christos Stavrakakis
    @wraps(func)
76 499d9bfe Christos Stavrakakis
    def wrapper(*args, **kwargs):
77 499d9bfe Christos Stavrakakis
        try:
78 499d9bfe Christos Stavrakakis
            return func(*args, **kwargs)
79 499d9bfe Christos Stavrakakis
        except AstakosClientException:
80 499d9bfe Christos Stavrakakis
            log.exception("Unexpected error")
81 499d9bfe Christos Stavrakakis
            raise faults.InternalServerError("Unexpected error")
82 499d9bfe Christos Stavrakakis
    return wrapper
83 499d9bfe Christos Stavrakakis
84 499d9bfe Christos Stavrakakis
85 499d9bfe Christos Stavrakakis
@handle_astakosclient_error
86 9122ffab Christos Stavrakakis
def issue_commission(user, source, provisions, name="",
87 629acc65 Giorgos Korfiatis
                     force=False, auto_accept=False):
88 bfe7ba3c Christos Stavrakakis
    """Issue a new commission to the quotaholder.
89 bfe7ba3c Christos Stavrakakis

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

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

165 11a54cb9 Christos Stavrakakis
    Get pending commissions from the quotaholder and resolve them
166 11a54cb9 Christos Stavrakakis
    to accepted and rejected, according to the state of the
167 11a54cb9 Christos Stavrakakis
    QuotaHolderSerial DB table. A pending commission in the quotaholder
168 11a54cb9 Christos Stavrakakis
    can exist in the QuotaHolderSerial table and be either accepted or
169 11a54cb9 Christos Stavrakakis
    rejected, or can not exist in this table, so it is rejected.
170 11a54cb9 Christos Stavrakakis

171 11a54cb9 Christos Stavrakakis
    """
172 11a54cb9 Christos Stavrakakis
173 11a54cb9 Christos Stavrakakis
    qh_pending = get_quotaholder_pending()
174 11a54cb9 Christos Stavrakakis
    if not qh_pending:
175 11a54cb9 Christos Stavrakakis
        return ([], [])
176 11a54cb9 Christos Stavrakakis
177 11a54cb9 Christos Stavrakakis
    qh_pending.sort()
178 11a54cb9 Christos Stavrakakis
    min_ = qh_pending[0]
179 11a54cb9 Christos Stavrakakis
180 11a54cb9 Christos Stavrakakis
    serials = QuotaHolderSerial.objects.filter(serial__gte=min_, pending=False)
181 2509ce17 Christos Stavrakakis
    accepted = serials.filter(accept=True).values_list('serial', flat=True)
182 11a54cb9 Christos Stavrakakis
    accepted = filter(lambda x: x in qh_pending, accepted)
183 11a54cb9 Christos Stavrakakis
184 11a54cb9 Christos Stavrakakis
    rejected = list(set(qh_pending) - set(accepted))
185 11a54cb9 Christos Stavrakakis
186 11a54cb9 Christos Stavrakakis
    return (accepted, rejected)
187 11a54cb9 Christos Stavrakakis
188 11a54cb9 Christos Stavrakakis
189 11a54cb9 Christos Stavrakakis
def get_quotaholder_pending():
190 629acc65 Giorgos Korfiatis
    qh = Quotaholder.get()
191 629acc65 Giorgos Korfiatis
    pending_serials = qh.get_pending_commissions(ASTAKOS_TOKEN)
192 11a54cb9 Christos Stavrakakis
    return pending_serials
193 5a70b1a3 Christos Stavrakakis
194 5a70b1a3 Christos Stavrakakis
195 629acc65 Giorgos Korfiatis
def render_overlimit_exception(e):
196 5a70b1a3 Christos Stavrakakis
    resource_name = {"vm": "Virtual Machine",
197 5a70b1a3 Christos Stavrakakis
                     "cpu": "CPU",
198 5a70b1a3 Christos Stavrakakis
                     "ram": "RAM",
199 8b41683a Christos Stavrakakis
                     "network.private": "Private Network",
200 8b41683a Christos Stavrakakis
                     "floating_ip": "Floating IP address"}
201 656cf771 Christos Stavrakakis
    details = json.loads(e.details)
202 629acc65 Giorgos Korfiatis
    data = details['overLimit']['data']
203 656cf771 Christos Stavrakakis
    usage = data["usage"]
204 656cf771 Christos Stavrakakis
    limit = data["limit"]
205 656cf771 Christos Stavrakakis
    available = limit - usage
206 629acc65 Giorgos Korfiatis
    provision = data['provision']
207 629acc65 Giorgos Korfiatis
    requested = provision['quantity']
208 629acc65 Giorgos Korfiatis
    resource = provision['resource']
209 629acc65 Giorgos Korfiatis
    res = resource.replace("cyclades.", "", 1)
210 5a70b1a3 Christos Stavrakakis
    try:
211 5a70b1a3 Christos Stavrakakis
        resource = resource_name[res]
212 5a70b1a3 Christos Stavrakakis
    except KeyError:
213 5a70b1a3 Christos Stavrakakis
        resource = res
214 5a70b1a3 Christos Stavrakakis
215 5a70b1a3 Christos Stavrakakis
    msg = "Resource Limit Exceeded for your account."
216 5a70b1a3 Christos Stavrakakis
    details = "Limit for resource '%s' exceeded for your account."\
217 629acc65 Giorgos Korfiatis
              " Available: %s, Requested: %s"\
218 629acc65 Giorgos Korfiatis
              % (resource, available, requested)
219 5a70b1a3 Christos Stavrakakis
    return msg, details
220 2509ce17 Christos Stavrakakis
221 2509ce17 Christos Stavrakakis
222 2509ce17 Christos Stavrakakis
@transaction.commit_manually
223 2509ce17 Christos Stavrakakis
def issue_and_accept_commission(resource, delete=False):
224 2509ce17 Christos Stavrakakis
    """Issue and accept a commission to Quotaholder.
225 2509ce17 Christos Stavrakakis

226 2509ce17 Christos Stavrakakis
    This function implements the Commission workflow, and must be called
227 2509ce17 Christos Stavrakakis
    exactly after and in the same transaction that created/updated the
228 2509ce17 Christos Stavrakakis
    resource. The workflow that implements is the following:
229 4ed25171 Christos Stavrakakis
    0) Resolve previous unresolved commission if exists
230 2509ce17 Christos Stavrakakis
    1) Issue commission and get a serial
231 2509ce17 Christos Stavrakakis
    2) Store the serial in DB and mark is as one to accept
232 2509ce17 Christos Stavrakakis
    3) Correlate the serial with the resource
233 2509ce17 Christos Stavrakakis
    4) COMMIT!
234 2509ce17 Christos Stavrakakis
    5) Accept commission to QH (reject if failed until 5)
235 2509ce17 Christos Stavrakakis
    6) Mark serial as resolved
236 2509ce17 Christos Stavrakakis
    7) COMMIT!
237 2509ce17 Christos Stavrakakis

238 2509ce17 Christos Stavrakakis
    """
239 4ed25171 Christos Stavrakakis
    previous_serial = resource.serial
240 4ed25171 Christos Stavrakakis
    if previous_serial is not None and not previous_serial.resolved:
241 4ed25171 Christos Stavrakakis
        if previous_serial.pending:
242 4ed25171 Christos Stavrakakis
            msg = "Issuing commission for resource '%s' while previous serial"\
243 4ed25171 Christos Stavrakakis
                  " '%s' is still pending." % (resource, previous_serial)
244 4ed25171 Christos Stavrakakis
            raise Exception(msg)
245 4ed25171 Christos Stavrakakis
        elif previous_serial.accept:
246 41a7fae7 Christos Stavrakakis
            accept_serial(previous_serial, strict=False)
247 4ed25171 Christos Stavrakakis
        else:
248 41a7fae7 Christos Stavrakakis
            reject_serial(previous_serial, strict=False)
249 4ed25171 Christos Stavrakakis
250 2509ce17 Christos Stavrakakis
    try:
251 2509ce17 Christos Stavrakakis
        # Convert resources in the format expected by Quotaholder
252 2509ce17 Christos Stavrakakis
        qh_resources = prepare_qh_resources(resource)
253 2509ce17 Christos Stavrakakis
        if delete:
254 2509ce17 Christos Stavrakakis
            qh_resources = reverse_quantities(qh_resources)
255 2509ce17 Christos Stavrakakis
256 2509ce17 Christos Stavrakakis
        # Issue commission and get the assigned serial
257 9122ffab Christos Stavrakakis
        commission_reason = ("client: api, resource: %s, delete: %s"
258 9122ffab Christos Stavrakakis
                             % (resource, delete))
259 9122ffab Christos Stavrakakis
        serial = issue_commission(user=resource.userid, source=DEFAULT_SOURCE,
260 9122ffab Christos Stavrakakis
                                  provisions=qh_resources,
261 9122ffab Christos Stavrakakis
                                  name=commission_reason)
262 2509ce17 Christos Stavrakakis
    except:
263 2509ce17 Christos Stavrakakis
        transaction.rollback()
264 2509ce17 Christos Stavrakakis
        raise
265 2509ce17 Christos Stavrakakis
266 2509ce17 Christos Stavrakakis
    try:
267 41a7fae7 Christos Stavrakakis
        # Mark the serial as one to accept and associate it with the resource
268 2509ce17 Christos Stavrakakis
        serial.pending = False
269 2509ce17 Christos Stavrakakis
        serial.accept = True
270 2509ce17 Christos Stavrakakis
        serial.save()
271 2509ce17 Christos Stavrakakis
        resource.serial = serial
272 2509ce17 Christos Stavrakakis
        resource.save()
273 2509ce17 Christos Stavrakakis
        transaction.commit()
274 41a7fae7 Christos Stavrakakis
        # Accept the commission to quotaholder
275 41a7fae7 Christos Stavrakakis
        accept_serial(serial)
276 41a7fae7 Christos Stavrakakis
        transaction.commit()
277 41a7fae7 Christos Stavrakakis
        return serial
278 2509ce17 Christos Stavrakakis
    except:
279 41a7fae7 Christos Stavrakakis
        log.exception("Unexpected ERROR")
280 2509ce17 Christos Stavrakakis
        transaction.rollback()
281 41a7fae7 Christos Stavrakakis
        reject_serial(serial)
282 2509ce17 Christos Stavrakakis
        transaction.commit()
283 2509ce17 Christos Stavrakakis
        raise
284 2509ce17 Christos Stavrakakis
285 2509ce17 Christos Stavrakakis
286 2509ce17 Christos Stavrakakis
def prepare_qh_resources(resource):
287 2509ce17 Christos Stavrakakis
    if isinstance(resource, VirtualMachine):
288 2509ce17 Christos Stavrakakis
        flavor = resource.flavor
289 2509ce17 Christos Stavrakakis
        return {'cyclades.vm': 1,
290 2509ce17 Christos Stavrakakis
                'cyclades.cpu': flavor.cpu,
291 41a7fae7 Christos Stavrakakis
                'cyclades.active_cpu': flavor.cpu,
292 2509ce17 Christos Stavrakakis
                'cyclades.disk': 1073741824 * flavor.disk,  # flavor.disk in GB
293 2509ce17 Christos Stavrakakis
                # 'public_ip': 1,
294 2509ce17 Christos Stavrakakis
                #'disk_template': flavor.disk_template,
295 41a7fae7 Christos Stavrakakis
                # flavor.ram is in MB
296 41a7fae7 Christos Stavrakakis
                'cyclades.ram': 1048576 * flavor.ram,
297 41a7fae7 Christos Stavrakakis
                'cyclades.active_ram': 1048576 * flavor.ram}
298 2509ce17 Christos Stavrakakis
    elif isinstance(resource, Network):
299 2509ce17 Christos Stavrakakis
        return {"cyclades.network.private": 1}
300 326c3ec8 Christos Stavrakakis
    elif isinstance(resource, IPAddress):
301 92d2d1ce Christos Stavrakakis
        if resource.floating_ip:
302 92d2d1ce Christos Stavrakakis
            return {"cyclades.floating_ip": 1}
303 2509ce17 Christos Stavrakakis
    else:
304 2509ce17 Christos Stavrakakis
        raise ValueError("Unknown Resource '%s'" % resource)
305 2509ce17 Christos Stavrakakis
306 2509ce17 Christos Stavrakakis
307 41a7fae7 Christos Stavrakakis
def get_commission_info(resource, action, action_fields=None):
308 41a7fae7 Christos Stavrakakis
    if isinstance(resource, VirtualMachine):
309 41a7fae7 Christos Stavrakakis
        flavor = resource.flavor
310 41a7fae7 Christos Stavrakakis
        resources = {"cyclades.vm": 1,
311 41a7fae7 Christos Stavrakakis
                     "cyclades.cpu": flavor.cpu,
312 41a7fae7 Christos Stavrakakis
                     "cyclades.disk": 1073741824 * flavor.disk,
313 41a7fae7 Christos Stavrakakis
                     "cyclades.ram": 1048576 * flavor.ram}
314 41a7fae7 Christos Stavrakakis
        online_resources = {"cyclades.active_cpu": flavor.cpu,
315 41a7fae7 Christos Stavrakakis
                            "cyclades.active_ram": 1048576 * flavor.ram}
316 bb649089 Christos Stavrakakis
        if action == "BUILD":
317 bb649089 Christos Stavrakakis
            resources.update(online_resources)
318 bb649089 Christos Stavrakakis
            return resources
319 41a7fae7 Christos Stavrakakis
        if action == "START":
320 41a7fae7 Christos Stavrakakis
            if resource.operstate == "STOPPED":
321 41a7fae7 Christos Stavrakakis
                return online_resources
322 41a7fae7 Christos Stavrakakis
            else:
323 41a7fae7 Christos Stavrakakis
                return None
324 41a7fae7 Christos Stavrakakis
        elif action == "STOP":
325 41a7fae7 Christos Stavrakakis
            if resource.operstate in ["STARTED", "BUILD", "ERROR"]:
326 41a7fae7 Christos Stavrakakis
                return reverse_quantities(online_resources)
327 41a7fae7 Christos Stavrakakis
            else:
328 41a7fae7 Christos Stavrakakis
                return None
329 41a7fae7 Christos Stavrakakis
        elif action == "REBOOT":
330 41a7fae7 Christos Stavrakakis
            if resource.operstate == "STOPPED":
331 41a7fae7 Christos Stavrakakis
                return online_resources
332 41a7fae7 Christos Stavrakakis
            else:
333 41a7fae7 Christos Stavrakakis
                return None
334 41a7fae7 Christos Stavrakakis
        elif action == "DESTROY":
335 41a7fae7 Christos Stavrakakis
            if resource.operstate in ["STARTED", "BUILD", "ERROR"]:
336 41a7fae7 Christos Stavrakakis
                resources.update(online_resources)
337 41a7fae7 Christos Stavrakakis
            return reverse_quantities(resources)
338 41a7fae7 Christos Stavrakakis
        elif action == "RESIZE" and action_fields:
339 41a7fae7 Christos Stavrakakis
            beparams = action_fields.get("beparams")
340 41a7fae7 Christos Stavrakakis
            cpu = beparams.get("vcpus", flavor.cpu)
341 41a7fae7 Christos Stavrakakis
            ram = beparams.get("maxmem", flavor.ram)
342 41a7fae7 Christos Stavrakakis
            return {"cyclades.cpu": cpu - flavor.cpu,
343 41a7fae7 Christos Stavrakakis
                    "cyclades.ram": 1048576 * (ram - flavor.ram)}
344 41a7fae7 Christos Stavrakakis
        else:
345 41a7fae7 Christos Stavrakakis
            #["CONNECT", "DISCONNECT", "SET_FIREWALL_PROFILE"]:
346 41a7fae7 Christos Stavrakakis
            return None
347 41a7fae7 Christos Stavrakakis
348 41a7fae7 Christos Stavrakakis
349 2509ce17 Christos Stavrakakis
def reverse_quantities(resources):
350 2509ce17 Christos Stavrakakis
    return dict((r, -s) for r, s in resources.items())
351 41a7fae7 Christos Stavrakakis
352 41a7fae7 Christos Stavrakakis
353 5c8076b6 Christos Stavrakakis
def handle_resource_commission(resource, action, commission_name,
354 5c8076b6 Christos Stavrakakis
                               commission_info=None, force=False,
355 5c8076b6 Christos Stavrakakis
                               auto_accept=False):
356 5c8076b6 Christos Stavrakakis
    """Handle a issuing of a commission for a resource.
357 5c8076b6 Christos Stavrakakis

358 5c8076b6 Christos Stavrakakis
    Create a new commission for a resource based on the action that
359 5c8076b6 Christos Stavrakakis
    is performed. If the resource has a previous pending commission,
360 5c8076b6 Christos Stavrakakis
    resolved it before issuing the new one.
361 5c8076b6 Christos Stavrakakis

362 5c8076b6 Christos Stavrakakis
    """
363 5c8076b6 Christos Stavrakakis
    # Try to resolve previous serial
364 5c8076b6 Christos Stavrakakis
    resolve_commission(resource.serial)
365 5c8076b6 Christos Stavrakakis
366 5c8076b6 Christos Stavrakakis
    # Check if action is quotable and issue the corresponding commission
367 5c8076b6 Christos Stavrakakis
    serial = None
368 5c8076b6 Christos Stavrakakis
    if commission_info is None:
369 5c8076b6 Christos Stavrakakis
        commission_info = get_commission_info(resource, action=action)
370 5c8076b6 Christos Stavrakakis
    if commission_info is not None:
371 5c8076b6 Christos Stavrakakis
        # Issue new commission, associate it with the resource
372 5c8076b6 Christos Stavrakakis
        if commission_name is None:
373 5c8076b6 Christos Stavrakakis
            commission_name = "client: api, resource %s" % resource
374 5c8076b6 Christos Stavrakakis
        serial = issue_commission(user=resource.userid,
375 5c8076b6 Christos Stavrakakis
                                  source=DEFAULT_SOURCE,
376 5c8076b6 Christos Stavrakakis
                                  provisions=commission_info,
377 5c8076b6 Christos Stavrakakis
                                  name=commission_name,
378 5c8076b6 Christos Stavrakakis
                                  force=False,
379 5c8076b6 Christos Stavrakakis
                                  auto_accept=False)
380 5c8076b6 Christos Stavrakakis
    resource.serial = serial
381 5c8076b6 Christos Stavrakakis
382 5c8076b6 Christos Stavrakakis
383 5c8076b6 Christos Stavrakakis
def resolve_commission(serial):
384 5c8076b6 Christos Stavrakakis
    if serial is None or serial.resolved:
385 5c8076b6 Christos Stavrakakis
        return
386 41a7fae7 Christos Stavrakakis
    log.warning("Resolving pending commission: %s", serial)
387 41a7fae7 Christos Stavrakakis
    if not serial.pending and serial.accept:
388 41a7fae7 Christos Stavrakakis
        accept_serial(serial)
389 41a7fae7 Christos Stavrakakis
    else:
390 41a7fae7 Christos Stavrakakis
        reject_serial(serial)