root / snf-cyclades-app / synnefo / quotas / __init__.py @ ba777b02
History | View | Annotate | Download (13.8 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 | ba777b02 | Giorgos Korfiatis | QUOTABLE_RESOURCES = [VirtualMachine, Network, IPAddress] |
47 | ba777b02 | Giorgos Korfiatis | |
48 | ba777b02 | Giorgos Korfiatis | |
49 | 629acc65 | Giorgos Korfiatis | DEFAULT_SOURCE = 'system'
|
50 | 656cf771 | Christos Stavrakakis | RESOURCES = [ |
51 | 656cf771 | Christos Stavrakakis | "cyclades.vm",
|
52 | 5083fc47 | Christos Stavrakakis | "cyclades.total_cpu",
|
53 | 656cf771 | Christos Stavrakakis | "cyclades.cpu",
|
54 | 656cf771 | Christos Stavrakakis | "cyclades.disk",
|
55 | 5083fc47 | Christos Stavrakakis | "cyclades.total_ram",
|
56 | 656cf771 | Christos Stavrakakis | "cyclades.ram",
|
57 | 8b41683a | Christos Stavrakakis | "cyclades.network.private",
|
58 | 8b41683a | Christos Stavrakakis | "cyclades.floating_ip",
|
59 | 656cf771 | Christos Stavrakakis | ] |
60 | bfe7ba3c | Christos Stavrakakis | |
61 | bfe7ba3c | Christos Stavrakakis | |
62 | 629acc65 | Giorgos Korfiatis | class Quotaholder(object): |
63 | 629acc65 | Giorgos Korfiatis | _object = None
|
64 | 629acc65 | Giorgos Korfiatis | |
65 | 629acc65 | Giorgos Korfiatis | @classmethod
|
66 | 629acc65 | Giorgos Korfiatis | def get(cls): |
67 | 629acc65 | Giorgos Korfiatis | if cls._object is None: |
68 | 4fb643b3 | Giorgos Korfiatis | cls._object = AstakosClient(ASTAKOS_TOKEN, |
69 | 4fb643b3 | Giorgos Korfiatis | ASTAKOS_AUTH_URL, |
70 | 4fb643b3 | Giorgos Korfiatis | use_pool=True,
|
71 | 4fb643b3 | Giorgos Korfiatis | retry=3,
|
72 | 4fb643b3 | Giorgos Korfiatis | logger=log) |
73 | 629acc65 | Giorgos Korfiatis | return cls._object
|
74 | bfe7ba3c | Christos Stavrakakis | |
75 | bfe7ba3c | Christos Stavrakakis | |
76 | 0dc4b304 | Giorgos Korfiatis | class AstakosClientExceptionHandler(object): |
77 | 0dc4b304 | Giorgos Korfiatis | def __init__(self, *args, **kwargs): |
78 | 0dc4b304 | Giorgos Korfiatis | pass
|
79 | 0dc4b304 | Giorgos Korfiatis | |
80 | 0dc4b304 | Giorgos Korfiatis | def __enter__(self): |
81 | 0dc4b304 | Giorgos Korfiatis | pass
|
82 | 0dc4b304 | Giorgos Korfiatis | |
83 | 0dc4b304 | Giorgos Korfiatis | def __exit__(self, exc_type, value, traceback): |
84 | 0dc4b304 | Giorgos Korfiatis | if value is not None: # exception |
85 | 0dc4b304 | Giorgos Korfiatis | if not isinstance(value, errors.AstakosClientException): |
86 | 0dc4b304 | Giorgos Korfiatis | return False # reraise |
87 | 0dc4b304 | Giorgos Korfiatis | if exc_type is errors.QuotaLimit: |
88 | 0dc4b304 | Giorgos Korfiatis | msg, details = render_overlimit_exception(value) |
89 | 0dc4b304 | Giorgos Korfiatis | raise faults.OverLimit(msg, details=details)
|
90 | 0dc4b304 | Giorgos Korfiatis | |
91 | 0dc4b304 | Giorgos Korfiatis | log.exception("Unexpected error %s" % value.message)
|
92 | 499d9bfe | Christos Stavrakakis | raise faults.InternalServerError("Unexpected error") |
93 | 499d9bfe | Christos Stavrakakis | |
94 | 499d9bfe | Christos Stavrakakis | |
95 | 16b959ce | Giorgos Korfiatis | def issue_commission(resource, action, name="", force=False, auto_accept=False, |
96 | 16b959ce | Giorgos Korfiatis | action_fields=None):
|
97 | bfe7ba3c | Christos Stavrakakis | """Issue a new commission to the quotaholder.
|
98 | bfe7ba3c | Christos Stavrakakis |
|
99 | bfe7ba3c | Christos Stavrakakis | Issue a new commission to the quotaholder, and create the
|
100 | bfe7ba3c | Christos Stavrakakis | corresponing QuotaHolderSerial object in DB.
|
101 | bfe7ba3c | Christos Stavrakakis |
|
102 | bfe7ba3c | Christos Stavrakakis | """
|
103 | bfe7ba3c | Christos Stavrakakis | |
104 | 16b959ce | Giorgos Korfiatis | provisions = get_commission_info(resource=resource, action=action, |
105 | 16b959ce | Giorgos Korfiatis | action_fields=action_fields) |
106 | 16b959ce | Giorgos Korfiatis | |
107 | 16b959ce | Giorgos Korfiatis | if provisions is None: |
108 | 16b959ce | Giorgos Korfiatis | return None |
109 | 16b959ce | Giorgos Korfiatis | |
110 | 16b959ce | Giorgos Korfiatis | user = resource.userid |
111 | 16b959ce | Giorgos Korfiatis | source = DEFAULT_SOURCE |
112 | 16b959ce | Giorgos Korfiatis | |
113 | 629acc65 | Giorgos Korfiatis | qh = Quotaholder.get() |
114 | 0dc4b304 | Giorgos Korfiatis | if True: # placeholder |
115 | 0dc4b304 | Giorgos Korfiatis | with AstakosClientExceptionHandler():
|
116 | 16b959ce | Giorgos Korfiatis | serial = qh.issue_one_commission(user, source, |
117 | 16b959ce | Giorgos Korfiatis | provisions, name=name, |
118 | 16b959ce | Giorgos Korfiatis | force=force, |
119 | 16b959ce | Giorgos Korfiatis | auto_accept=auto_accept) |
120 | bfe7ba3c | Christos Stavrakakis | |
121 | ba777b02 | Giorgos Korfiatis | if not serial: |
122 | b14f55b5 | Christos Stavrakakis | raise Exception("No serial") |
123 | bfe7ba3c | Christos Stavrakakis | |
124 | ba777b02 | Giorgos Korfiatis | serial_info = {"serial": serial}
|
125 | ba777b02 | Giorgos Korfiatis | if auto_accept:
|
126 | ba777b02 | Giorgos Korfiatis | serial_info["pending"] = False |
127 | ba777b02 | Giorgos Korfiatis | serial_info["accept"] = True |
128 | ba777b02 | Giorgos Korfiatis | serial_info["resolved"] = True |
129 | ba777b02 | Giorgos Korfiatis | |
130 | ba777b02 | Giorgos Korfiatis | serial = QuotaHolderSerial.objects.create(**serial_info) |
131 | ba777b02 | Giorgos Korfiatis | |
132 | ba777b02 | Giorgos Korfiatis | # Correlate the serial with the resource. Resolved serials are not
|
133 | ba777b02 | Giorgos Korfiatis | # attached to resources
|
134 | ba777b02 | Giorgos Korfiatis | if not auto_accept: |
135 | ba777b02 | Giorgos Korfiatis | resource.serial = serial |
136 | ba777b02 | Giorgos Korfiatis | resource.save() |
137 | bfe7ba3c | Christos Stavrakakis | |
138 | ba777b02 | Giorgos Korfiatis | return serial
|
139 | ba777b02 | Giorgos Korfiatis | |
140 | ba777b02 | Giorgos Korfiatis | |
141 | ba777b02 | Giorgos Korfiatis | def accept_resource_serial(resource, strict=True): |
142 | ba777b02 | Giorgos Korfiatis | serial = resource.serial |
143 | f4d624c6 | Giorgos Korfiatis | assert serial.pending or serial.accept, "%s can't be accepted" % serial |
144 | ba777b02 | Giorgos Korfiatis | log.debug("Accepting serial %s of resource %s", serial, resource)
|
145 | ba777b02 | Giorgos Korfiatis | _resolve_commissions(accept=[serial.serial], strict=strict) |
146 | ba777b02 | Giorgos Korfiatis | resource.serial = None
|
147 | ba777b02 | Giorgos Korfiatis | resource.save() |
148 | ba777b02 | Giorgos Korfiatis | return resource
|
149 | 41a7fae7 | Christos Stavrakakis | |
150 | 41a7fae7 | Christos Stavrakakis | |
151 | ba777b02 | Giorgos Korfiatis | def reject_resource_serial(resource, strict=True): |
152 | ba777b02 | Giorgos Korfiatis | serial = resource.serial |
153 | f4d624c6 | Giorgos Korfiatis | assert serial.pending or not serial.accept, "%s can't be rejected" % serial |
154 | ba777b02 | Giorgos Korfiatis | log.debug("Rejecting serial %s of resource %s", serial, resource)
|
155 | ba777b02 | Giorgos Korfiatis | _resolve_commissions(reject=[serial.serial], strict=strict) |
156 | ba777b02 | Giorgos Korfiatis | resource.serial = None
|
157 | ba777b02 | Giorgos Korfiatis | resource.save() |
158 | ba777b02 | Giorgos Korfiatis | return resource
|
159 | 41a7fae7 | Christos Stavrakakis | |
160 | 41a7fae7 | Christos Stavrakakis | |
161 | ba777b02 | Giorgos Korfiatis | def _resolve_commissions(accept=None, reject=None, strict=True): |
162 | 629acc65 | Giorgos Korfiatis | if accept is None: |
163 | 629acc65 | Giorgos Korfiatis | accept = [] |
164 | 629acc65 | Giorgos Korfiatis | if reject is None: |
165 | 629acc65 | Giorgos Korfiatis | reject = [] |
166 | 11a54cb9 | Christos Stavrakakis | |
167 | 629acc65 | Giorgos Korfiatis | qh = Quotaholder.get() |
168 | 0dc4b304 | Giorgos Korfiatis | with AstakosClientExceptionHandler():
|
169 | 0dc4b304 | Giorgos Korfiatis | response = qh.resolve_commissions(accept, reject) |
170 | 5db3a1e6 | Christos Stavrakakis | |
171 | f4d624c6 | Giorgos Korfiatis | accepted = response.get("accepted", [])
|
172 | f4d624c6 | Giorgos Korfiatis | rejected = response.get("rejected", [])
|
173 | f4d624c6 | Giorgos Korfiatis | |
174 | f4d624c6 | Giorgos Korfiatis | if accepted:
|
175 | f4d624c6 | Giorgos Korfiatis | QuotaHolderSerial.objects.filter(serial__in=accepted).update( |
176 | f4d624c6 | Giorgos Korfiatis | accept=True, pending=False, resolved=True) |
177 | f4d624c6 | Giorgos Korfiatis | if rejected:
|
178 | f4d624c6 | Giorgos Korfiatis | QuotaHolderSerial.objects.filter(serial__in=rejected).update( |
179 | f4d624c6 | Giorgos Korfiatis | accept=False, pending=False, resolved=True) |
180 | 3af1fb4b | Christos Stavrakakis | |
181 | 5db3a1e6 | Christos Stavrakakis | if strict:
|
182 | 5db3a1e6 | Christos Stavrakakis | failed = response["failed"]
|
183 | 5db3a1e6 | Christos Stavrakakis | if failed:
|
184 | 5db3a1e6 | Christos Stavrakakis | log.error("Unexpected error while resolving commissions: %s",
|
185 | 5db3a1e6 | Christos Stavrakakis | failed) |
186 | 5db3a1e6 | Christos Stavrakakis | |
187 | 5db3a1e6 | Christos Stavrakakis | return response
|
188 | 11a54cb9 | Christos Stavrakakis | |
189 | 11a54cb9 | Christos Stavrakakis | |
190 | ba777b02 | Giorgos Korfiatis | def reconcile_resolve_commissions(accept=None, reject=None, strict=True): |
191 | ba777b02 | Giorgos Korfiatis | response = _resolve_commissions(accept=accept, |
192 | ba777b02 | Giorgos Korfiatis | reject=reject, |
193 | ba777b02 | Giorgos Korfiatis | strict=strict) |
194 | ba777b02 | Giorgos Korfiatis | affected = response.get("accepted", []) + response.get("rejected", []) |
195 | ba777b02 | Giorgos Korfiatis | for resource in QUOTABLE_RESOURCES: |
196 | ba777b02 | Giorgos Korfiatis | resource.objects.filter(serial__in=affected).update(serial=None)
|
197 | ba777b02 | Giorgos Korfiatis | |
198 | ba777b02 | Giorgos Korfiatis | |
199 | 11a54cb9 | Christos Stavrakakis | def resolve_pending_commissions(): |
200 | 11a54cb9 | Christos Stavrakakis | """Resolve quotaholder pending commissions.
|
201 | 11a54cb9 | Christos Stavrakakis |
|
202 | 11a54cb9 | Christos Stavrakakis | Get pending commissions from the quotaholder and resolve them
|
203 | 11a54cb9 | Christos Stavrakakis | to accepted and rejected, according to the state of the
|
204 | 11a54cb9 | Christos Stavrakakis | QuotaHolderSerial DB table. A pending commission in the quotaholder
|
205 | 11a54cb9 | Christos Stavrakakis | can exist in the QuotaHolderSerial table and be either accepted or
|
206 | 8d5795b4 | Christos Stavrakakis | rejected, or cannot exist in this table, so it is rejected.
|
207 | 11a54cb9 | Christos Stavrakakis |
|
208 | 11a54cb9 | Christos Stavrakakis | """
|
209 | 11a54cb9 | Christos Stavrakakis | |
210 | 11a54cb9 | Christos Stavrakakis | qh_pending = get_quotaholder_pending() |
211 | 11a54cb9 | Christos Stavrakakis | if not qh_pending: |
212 | 11a54cb9 | Christos Stavrakakis | return ([], [])
|
213 | 11a54cb9 | Christos Stavrakakis | |
214 | 11a54cb9 | Christos Stavrakakis | qh_pending.sort() |
215 | 11a54cb9 | Christos Stavrakakis | min_ = qh_pending[0]
|
216 | 11a54cb9 | Christos Stavrakakis | |
217 | 11a54cb9 | Christos Stavrakakis | serials = QuotaHolderSerial.objects.filter(serial__gte=min_, pending=False)
|
218 | 2509ce17 | Christos Stavrakakis | accepted = serials.filter(accept=True).values_list('serial', flat=True) |
219 | 11a54cb9 | Christos Stavrakakis | accepted = filter(lambda x: x in qh_pending, accepted) |
220 | 11a54cb9 | Christos Stavrakakis | |
221 | 11a54cb9 | Christos Stavrakakis | rejected = list(set(qh_pending) - set(accepted)) |
222 | 11a54cb9 | Christos Stavrakakis | |
223 | 11a54cb9 | Christos Stavrakakis | return (accepted, rejected)
|
224 | 11a54cb9 | Christos Stavrakakis | |
225 | 11a54cb9 | Christos Stavrakakis | |
226 | 11a54cb9 | Christos Stavrakakis | def get_quotaholder_pending(): |
227 | 629acc65 | Giorgos Korfiatis | qh = Quotaholder.get() |
228 | e407f159 | Ilias Tsitsimpis | pending_serials = qh.get_pending_commissions() |
229 | 11a54cb9 | Christos Stavrakakis | return pending_serials
|
230 | 5a70b1a3 | Christos Stavrakakis | |
231 | 5a70b1a3 | Christos Stavrakakis | |
232 | 629acc65 | Giorgos Korfiatis | def render_overlimit_exception(e): |
233 | 5a70b1a3 | Christos Stavrakakis | resource_name = {"vm": "Virtual Machine", |
234 | 5a70b1a3 | Christos Stavrakakis | "cpu": "CPU", |
235 | 5a70b1a3 | Christos Stavrakakis | "ram": "RAM", |
236 | 8b41683a | Christos Stavrakakis | "network.private": "Private Network", |
237 | 8b41683a | Christos Stavrakakis | "floating_ip": "Floating IP address"} |
238 | 656cf771 | Christos Stavrakakis | details = json.loads(e.details) |
239 | 629acc65 | Giorgos Korfiatis | data = details['overLimit']['data'] |
240 | 656cf771 | Christos Stavrakakis | usage = data["usage"]
|
241 | 656cf771 | Christos Stavrakakis | limit = data["limit"]
|
242 | 656cf771 | Christos Stavrakakis | available = limit - usage |
243 | 629acc65 | Giorgos Korfiatis | provision = data['provision']
|
244 | 629acc65 | Giorgos Korfiatis | requested = provision['quantity']
|
245 | 629acc65 | Giorgos Korfiatis | resource = provision['resource']
|
246 | 629acc65 | Giorgos Korfiatis | res = resource.replace("cyclades.", "", 1) |
247 | 5a70b1a3 | Christos Stavrakakis | try:
|
248 | 5a70b1a3 | Christos Stavrakakis | resource = resource_name[res] |
249 | 5a70b1a3 | Christos Stavrakakis | except KeyError: |
250 | 5a70b1a3 | Christos Stavrakakis | resource = res |
251 | 5a70b1a3 | Christos Stavrakakis | |
252 | 5a70b1a3 | Christos Stavrakakis | msg = "Resource Limit Exceeded for your account."
|
253 | 5a70b1a3 | Christos Stavrakakis | details = "Limit for resource '%s' exceeded for your account."\
|
254 | 629acc65 | Giorgos Korfiatis | " Available: %s, Requested: %s"\
|
255 | 629acc65 | Giorgos Korfiatis | % (resource, available, requested) |
256 | 5a70b1a3 | Christos Stavrakakis | return msg, details
|
257 | 2509ce17 | Christos Stavrakakis | |
258 | 2509ce17 | Christos Stavrakakis | |
259 | 21eb7404 | Christos Stavrakakis | @transaction.commit_on_success
|
260 | 368d879e | Giorgos Korfiatis | def issue_and_accept_commission(resource, action="BUILD", action_fields=None): |
261 | 2509ce17 | Christos Stavrakakis | """Issue and accept a commission to Quotaholder.
|
262 | 2509ce17 | Christos Stavrakakis |
|
263 | 2509ce17 | Christos Stavrakakis | This function implements the Commission workflow, and must be called
|
264 | 2509ce17 | Christos Stavrakakis | exactly after and in the same transaction that created/updated the
|
265 | 2509ce17 | Christos Stavrakakis | resource. The workflow that implements is the following:
|
266 | 4ed25171 | Christos Stavrakakis | 0) Resolve previous unresolved commission if exists
|
267 | 21eb7404 | Christos Stavrakakis | 1) Issue commission, get a serial and correlate it with the resource
|
268 | 21eb7404 | Christos Stavrakakis | 2) Store the serial in DB as a serial to accept
|
269 | 21eb7404 | Christos Stavrakakis | 3) COMMIT!
|
270 | 21eb7404 | Christos Stavrakakis | 4) Accept commission to QH
|
271 | 2509ce17 | Christos Stavrakakis |
|
272 | 2509ce17 | Christos Stavrakakis | """
|
273 | 368d879e | Giorgos Korfiatis | commission_reason = ("client: api, resource: %s, action: %s"
|
274 | 368d879e | Giorgos Korfiatis | % (resource, action)) |
275 | 21eb7404 | Christos Stavrakakis | serial = handle_resource_commission(resource=resource, action=action, |
276 | 368d879e | Giorgos Korfiatis | action_fields=action_fields, |
277 | 21eb7404 | Christos Stavrakakis | commission_name=commission_reason) |
278 | 4ed25171 | Christos Stavrakakis | |
279 | ba777b02 | Giorgos Korfiatis | if serial is None: |
280 | ba777b02 | Giorgos Korfiatis | return
|
281 | ba777b02 | Giorgos Korfiatis | |
282 | 21eb7404 | Christos Stavrakakis | # Mark the serial as one to accept and associate it with the resource
|
283 | 21eb7404 | Christos Stavrakakis | serial.pending = False
|
284 | 21eb7404 | Christos Stavrakakis | serial.accept = True
|
285 | 21eb7404 | Christos Stavrakakis | serial.save() |
286 | 21eb7404 | Christos Stavrakakis | transaction.commit() |
287 | 2509ce17 | Christos Stavrakakis | |
288 | 2509ce17 | Christos Stavrakakis | try:
|
289 | 41a7fae7 | Christos Stavrakakis | # Accept the commission to quotaholder
|
290 | ba777b02 | Giorgos Korfiatis | accept_resource_serial(resource) |
291 | 2509ce17 | Christos Stavrakakis | except:
|
292 | 21eb7404 | Christos Stavrakakis | # Do not crash if we can not accept commission to Quotaholder. Quotas
|
293 | 21eb7404 | Christos Stavrakakis | # have already been reserved and the resource already exists in DB.
|
294 | 21eb7404 | Christos Stavrakakis | # Just log the error
|
295 | ba777b02 | Giorgos Korfiatis | log.exception("Failed to accept commission: %s", resource.serial)
|
296 | 2509ce17 | Christos Stavrakakis | |
297 | 2509ce17 | Christos Stavrakakis | |
298 | 41a7fae7 | Christos Stavrakakis | def get_commission_info(resource, action, action_fields=None): |
299 | 41a7fae7 | Christos Stavrakakis | if isinstance(resource, VirtualMachine): |
300 | 41a7fae7 | Christos Stavrakakis | flavor = resource.flavor |
301 | 41a7fae7 | Christos Stavrakakis | resources = {"cyclades.vm": 1, |
302 | 5083fc47 | Christos Stavrakakis | "cyclades.total_cpu": flavor.cpu,
|
303 | 41a7fae7 | Christos Stavrakakis | "cyclades.disk": 1073741824 * flavor.disk, |
304 | 5083fc47 | Christos Stavrakakis | "cyclades.total_ram": 1048576 * flavor.ram} |
305 | 5083fc47 | Christos Stavrakakis | online_resources = {"cyclades.cpu": flavor.cpu,
|
306 | 5083fc47 | Christos Stavrakakis | "cyclades.ram": 1048576 * flavor.ram} |
307 | bb649089 | Christos Stavrakakis | if action == "BUILD": |
308 | bb649089 | Christos Stavrakakis | resources.update(online_resources) |
309 | bb649089 | Christos Stavrakakis | return resources
|
310 | 41a7fae7 | Christos Stavrakakis | if action == "START": |
311 | 41a7fae7 | Christos Stavrakakis | if resource.operstate == "STOPPED": |
312 | 41a7fae7 | Christos Stavrakakis | return online_resources
|
313 | 41a7fae7 | Christos Stavrakakis | else:
|
314 | 41a7fae7 | Christos Stavrakakis | return None |
315 | 41a7fae7 | Christos Stavrakakis | elif action == "STOP": |
316 | 41a7fae7 | Christos Stavrakakis | if resource.operstate in ["STARTED", "BUILD", "ERROR"]: |
317 | 41a7fae7 | Christos Stavrakakis | return reverse_quantities(online_resources)
|
318 | 41a7fae7 | Christos Stavrakakis | else:
|
319 | 41a7fae7 | Christos Stavrakakis | return None |
320 | 41a7fae7 | Christos Stavrakakis | elif action == "REBOOT": |
321 | 41a7fae7 | Christos Stavrakakis | if resource.operstate == "STOPPED": |
322 | 41a7fae7 | Christos Stavrakakis | return online_resources
|
323 | 41a7fae7 | Christos Stavrakakis | else:
|
324 | 41a7fae7 | Christos Stavrakakis | return None |
325 | 41a7fae7 | Christos Stavrakakis | elif action == "DESTROY": |
326 | 41a7fae7 | Christos Stavrakakis | if resource.operstate in ["STARTED", "BUILD", "ERROR"]: |
327 | 41a7fae7 | Christos Stavrakakis | resources.update(online_resources) |
328 | 41a7fae7 | Christos Stavrakakis | return reverse_quantities(resources)
|
329 | 41a7fae7 | Christos Stavrakakis | elif action == "RESIZE" and action_fields: |
330 | 41a7fae7 | Christos Stavrakakis | beparams = action_fields.get("beparams")
|
331 | 41a7fae7 | Christos Stavrakakis | cpu = beparams.get("vcpus", flavor.cpu)
|
332 | 41a7fae7 | Christos Stavrakakis | ram = beparams.get("maxmem", flavor.ram)
|
333 | 5083fc47 | Christos Stavrakakis | return {"cyclades.total_cpu": cpu - flavor.cpu, |
334 | 5083fc47 | Christos Stavrakakis | "cyclades.total_ram": 1048576 * (ram - flavor.ram)} |
335 | 41a7fae7 | Christos Stavrakakis | else:
|
336 | 41a7fae7 | Christos Stavrakakis | #["CONNECT", "DISCONNECT", "SET_FIREWALL_PROFILE"]:
|
337 | 41a7fae7 | Christos Stavrakakis | return None |
338 | 16b959ce | Giorgos Korfiatis | elif isinstance(resource, Network): |
339 | 16b959ce | Giorgos Korfiatis | resources = {"cyclades.network.private": 1} |
340 | 16b959ce | Giorgos Korfiatis | if action == "BUILD": |
341 | 16b959ce | Giorgos Korfiatis | return resources
|
342 | 16b959ce | Giorgos Korfiatis | elif action == "DESTROY": |
343 | 16b959ce | Giorgos Korfiatis | return reverse_quantities(resources)
|
344 | 44183264 | Christos Stavrakakis | elif isinstance(resource, IPAddress): |
345 | 44183264 | Christos Stavrakakis | if resource.floating_ip:
|
346 | 44183264 | Christos Stavrakakis | resources = {"cyclades.floating_ip": 1} |
347 | 44183264 | Christos Stavrakakis | if action == "BUILD": |
348 | 44183264 | Christos Stavrakakis | return resources
|
349 | 44183264 | Christos Stavrakakis | elif action == "DESTROY": |
350 | 44183264 | Christos Stavrakakis | return reverse_quantities(resources)
|
351 | 44183264 | Christos Stavrakakis | else:
|
352 | 44183264 | Christos Stavrakakis | return None |
353 | 41a7fae7 | Christos Stavrakakis | |
354 | 41a7fae7 | Christos Stavrakakis | |
355 | 2509ce17 | Christos Stavrakakis | def reverse_quantities(resources): |
356 | 2509ce17 | Christos Stavrakakis | return dict((r, -s) for r, s in resources.items()) |
357 | 41a7fae7 | Christos Stavrakakis | |
358 | 41a7fae7 | Christos Stavrakakis | |
359 | 5c8076b6 | Christos Stavrakakis | def handle_resource_commission(resource, action, commission_name, |
360 | 16b959ce | Giorgos Korfiatis | force=False, auto_accept=False, |
361 | 16b959ce | Giorgos Korfiatis | action_fields=None):
|
362 | 5c8076b6 | Christos Stavrakakis | """Handle a issuing of a commission for a resource.
|
363 | 5c8076b6 | Christos Stavrakakis |
|
364 | 5c8076b6 | Christos Stavrakakis | Create a new commission for a resource based on the action that
|
365 | 5c8076b6 | Christos Stavrakakis | is performed. If the resource has a previous pending commission,
|
366 | 5c8076b6 | Christos Stavrakakis | resolved it before issuing the new one.
|
367 | 5c8076b6 | Christos Stavrakakis |
|
368 | 5c8076b6 | Christos Stavrakakis | """
|
369 | 1fdd8d69 | Christos Stavrakakis | # Try to resolve previous serial:
|
370 | 1fdd8d69 | Christos Stavrakakis | # If action is DESTROY, we must always reject the previous commission,
|
371 | 1fdd8d69 | Christos Stavrakakis | # since multiple DESTROY actions are allowed in the same resource (e.g. VM)
|
372 | 1fdd8d69 | Christos Stavrakakis | # The one who succeeds will be finally accepted, and all other will be
|
373 | 1fdd8d69 | Christos Stavrakakis | # rejected
|
374 | 1fdd8d69 | Christos Stavrakakis | force = force or (action == "DESTROY") |
375 | ba777b02 | Giorgos Korfiatis | resolve_resource_commission(resource, force=force) |
376 | 5c8076b6 | Christos Stavrakakis | |
377 | 16b959ce | Giorgos Korfiatis | serial = issue_commission(resource, action, name=commission_name, |
378 | 16b959ce | Giorgos Korfiatis | force=force, auto_accept=auto_accept, |
379 | 16b959ce | Giorgos Korfiatis | action_fields=action_fields) |
380 | 21eb7404 | Christos Stavrakakis | return serial
|
381 | 5c8076b6 | Christos Stavrakakis | |
382 | 5c8076b6 | Christos Stavrakakis | |
383 | fb540e3a | Giorgos Korfiatis | class ResolveError(Exception): |
384 | fb540e3a | Giorgos Korfiatis | pass
|
385 | fb540e3a | Giorgos Korfiatis | |
386 | fb540e3a | Giorgos Korfiatis | |
387 | ba777b02 | Giorgos Korfiatis | def resolve_resource_commission(resource, force=False): |
388 | ba777b02 | Giorgos Korfiatis | serial = resource.serial |
389 | 5c8076b6 | Christos Stavrakakis | if serial is None or serial.resolved: |
390 | 5c8076b6 | Christos Stavrakakis | return
|
391 | fb540e3a | Giorgos Korfiatis | if serial.pending and not force: |
392 | fb540e3a | Giorgos Korfiatis | m = "Could not resolve commission: serial %s is undecided" % serial
|
393 | fb540e3a | Giorgos Korfiatis | raise ResolveError(m)
|
394 | 41a7fae7 | Christos Stavrakakis | log.warning("Resolving pending commission: %s", serial)
|
395 | 41a7fae7 | Christos Stavrakakis | if not serial.pending and serial.accept: |
396 | ba777b02 | Giorgos Korfiatis | accept_resource_serial(resource) |
397 | 41a7fae7 | Christos Stavrakakis | else:
|
398 | ba777b02 | Giorgos Korfiatis | reject_resource_serial(resource) |