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) |