Revision 99667854
b/docs/compute-api-guide.rst | ||
---|---|---|
1623 | 1623 |
`Reboot <#reboot-server>`_ ✔ ✔ |
1624 | 1624 |
`Get Console <#get-server-console>`_ ✔ **✘** |
1625 | 1625 |
`Set Firewall <#set-server-firewall-profile>`_ ✔ **✘** |
1626 |
`Reassign <#reassign-server>`_ ✔ **✘** |
|
1626 | 1627 |
`Change Admin Password <#os-compute-specific>`_ **✘** ✔ |
1627 | 1628 |
`Rebuild <#os-compute-specific>`_ **✘** ✔ |
1628 | 1629 |
`Resize <#os-compute-specific>`_ **✘** ✔ |
... | ... | |
1804 | 1805 |
|
1805 | 1806 |
.. note:: Response body should be empty |
1806 | 1807 |
|
1808 |
Reassign Server |
|
1809 |
............... |
|
1810 |
|
|
1811 |
This operation assigns the VM to a different project. |
|
1812 |
|
|
1813 |
Request body contents:: |
|
1814 |
|
|
1815 |
reassign: { project: <project-id>} |
|
1816 |
|
|
1817 |
*Example Action reassign: JSON** |
|
1818 |
|
|
1819 |
.. code-block:: javascript |
|
1820 |
|
|
1821 |
{"reassign": {"project": "9969f2fd-86d8-45d6-9106-5e251f7dd92f"}} |
|
1822 |
|
|
1823 |
.. note:: Response body should be empty |
|
1824 |
|
|
1807 | 1825 |
OS/Compute Specific |
1808 | 1826 |
................... |
1809 | 1827 |
|
... | ... | |
2756 | 2774 |
`Delete <#delete-network>`_ ``/networks/<network-id>`` DELETE |
2757 | 2775 |
`Connect <#connect-network-to-server>`_ ``/networks/<network-id>/action`` POST |
2758 | 2776 |
`Disconnect <#disconnect-network-from-server>`_ ``/networks/<network-id>/action`` POST |
2777 |
`Reassign <#reassign-network>`_ ``/networks/<network-id>/action`` POST |
|
2759 | 2778 |
=============================================== ================================= ====== |
2760 | 2779 |
|
2761 | 2780 |
|
... | ... | |
3331 | 3350 |
|
3332 | 3351 |
.. note:: In case of a 202 code, the request body should be empty |
3333 | 3352 |
|
3353 |
Reassign Network |
|
3354 |
................ |
|
3355 |
|
|
3356 |
Assign a network to a different project. |
|
3357 |
|
|
3358 |
.. rubric:: Request |
|
3359 |
|
|
3360 |
================================= ====== |
|
3361 |
URI Method |
|
3362 |
================================= ====== |
|
3363 |
``/networks/<network-id>/action`` POST |
|
3364 |
================================= ====== |
|
3365 |
|
|
3366 |
* **network-id** is the identifier of the network |
|
3367 |
|
|
3368 |
| |
|
3369 |
|
|
3370 |
============== ========================= |
|
3371 |
Request Header Value |
|
3372 |
============== ========================= |
|
3373 |
X-Auth-Token User authentication token |
|
3374 |
Content-Type Type or request body |
|
3375 |
Content-Length Length of request body |
|
3376 |
============== ========================= |
|
3377 |
|
|
3378 |
**Example Request Headers**:: |
|
3379 |
|
|
3380 |
X-Auth-Token: z31uRXUn1LZy45p1r7V== |
|
3381 |
Content-Type: application/json |
|
3382 |
Content-Length: 31 |
|
3383 |
|
|
3384 |
.. note:: Request parameters should be empty |
|
3385 |
|
|
3386 |
Response body content (reassign):: |
|
3387 |
|
|
3388 |
reassign {project: <project-id>} |
|
3389 |
|
|
3390 |
*Example Action Reassign: JSON* |
|
3391 |
|
|
3392 |
.. code-block:: javascript |
|
3393 |
|
|
3394 |
{"reassign" : {"project" : "9969f2fd-86d8-45d6-9106-5e251f7dd92f"}} |
|
3395 |
|
|
3396 |
.. rubric:: Response |
|
3397 |
|
|
3398 |
=========================== ===================== |
|
3399 |
Return Code Description |
|
3400 |
=========================== ===================== |
|
3401 |
200 (OK) Request succeeded |
|
3402 |
400 (Bad Request) Malformed request |
|
3403 |
401 (Unauthorized) Missing or expired user token |
|
3404 |
403 (Forbidden) Not allowed to modify this network (e.g. public) |
|
3405 |
404 (Not Found) Network not found |
|
3406 |
500 (Internal Server Error) The request cannot be completed because of an |
|
3407 |
\ internal error |
|
3408 |
503 (Service Unavailable) The service is not currently available |
|
3409 |
=========================== ===================== |
|
3410 |
|
|
3411 |
.. note:: In case of a 200 code, the request body should be empty |
|
3412 |
|
|
3334 | 3413 |
Index of Attributes |
3335 | 3414 |
------------------- |
3336 | 3415 |
|
b/snf-cyclades-app/synnefo/api/floating_ips.py | ||
---|---|---|
62 | 62 |
'synnefo.api.floating_ips', |
63 | 63 |
(r'^(?:/|.json|.xml)?$', 'demux'), |
64 | 64 |
(r'^/detail(?:.json|.xml)?$', 'list_floating_ips', {'detail': True}), |
65 |
(r'^/(\w+)(?:/|.json|.xml)?$', 'floating_ip_demux')) |
|
65 |
(r'^/(\w+)(?:/|.json|.xml)?$', 'floating_ip_demux'), |
|
66 |
(r'^/(\w+)/action(?:.json|.xml)?$', 'floating_ip_action_demux'), |
|
67 |
) |
|
66 | 68 |
|
67 | 69 |
|
68 | 70 |
def demux(request): |
... | ... | |
87 | 89 |
allowed_methods=['GET', 'DELETE']) |
88 | 90 |
|
89 | 91 |
|
92 |
@api.api_method(http_method='POST', user_required=True, logger=log, |
|
93 |
serializations=["json"]) |
|
94 |
def floating_ip_action_demux(request, floating_ip_id): |
|
95 |
userid = request.user_uniq |
|
96 |
req = utils.get_request_dict(request) |
|
97 |
log.debug('floating_ip_action %s %s', floating_ip_id, req) |
|
98 |
if len(req) != 1: |
|
99 |
raise faults.BadRequest('Malformed request.') |
|
100 |
floating_ip = util.get_floating_ip_by_id(userid, |
|
101 |
floating_ip_id, |
|
102 |
for_update=True) |
|
103 |
action = req.keys()[0] |
|
104 |
try: |
|
105 |
f = FLOATING_IP_ACTIONS[action] |
|
106 |
except KeyError: |
|
107 |
raise faults.BadRequest("Action %s not supported." % action) |
|
108 |
action_args = req[action] |
|
109 |
if not isinstance(action_args, dict): |
|
110 |
raise faults.BadRequest("Invalid argument.") |
|
111 |
|
|
112 |
return f(request, floating_ip, action_args) |
|
113 |
|
|
114 |
|
|
90 | 115 |
def ip_to_dict(floating_ip): |
91 | 116 |
machine_id = None |
92 | 117 |
port_id = None |
... | ... | |
236 | 261 |
return HttpResponse(data, status=200) |
237 | 262 |
|
238 | 263 |
|
264 |
@transaction.commit_on_success |
|
265 |
def reassign(request, floating_ip, args): |
|
266 |
project = args.get("project") |
|
267 |
if project is None: |
|
268 |
raise faults.BadRequest("Missing 'project' attribute.") |
|
269 |
ips.reassign_floating_ip(floating_ip, project) |
|
270 |
return HttpResponse(status=200) |
|
271 |
|
|
272 |
|
|
273 |
FLOATING_IP_ACTIONS = { |
|
274 |
"reassign": reassign, |
|
275 |
} |
|
276 |
|
|
277 |
|
|
239 | 278 |
def network_to_floating_ip_pool(network): |
240 | 279 |
"""Convert a 'Network' object to a floating IP pool dict.""" |
241 | 280 |
total, free = network.ip_count() |
b/snf-cyclades-app/synnefo/api/networks.py | ||
---|---|---|
40 | 40 |
from django.template.loader import render_to_string |
41 | 41 |
|
42 | 42 |
from snf_django.lib import api |
43 |
from snf_django.lib.api import utils |
|
43 | 44 |
|
44 | 45 |
from synnefo.api import util |
45 | 46 |
from synnefo.db.models import Network |
... | ... | |
53 | 54 |
'synnefo.api.networks', |
54 | 55 |
(r'^(?:/|.json|.xml)?$', 'demux'), |
55 | 56 |
(r'^/detail(?:.json|.xml)?$', 'list_networks', {'detail': True}), |
56 |
(r'^/(\w+)(?:/|.json|.xml)?$', 'network_demux')) |
|
57 |
(r'^/(\w+)(?:/|.json|.xml)?$', 'network_demux'), |
|
58 |
(r'^/(\w+)/action(?:/|.json|.xml)?$', 'network_action_demux'), |
|
59 |
) |
|
57 | 60 |
|
58 | 61 |
|
59 | 62 |
def demux(request): |
... | ... | |
81 | 84 |
'DELETE']) |
82 | 85 |
|
83 | 86 |
|
87 |
@api.api_method(http_method='POST', user_required=True, logger=log) |
|
88 |
def network_action_demux(request, network_id): |
|
89 |
req = utils.get_request_dict(request) |
|
90 |
network = util.get_network(network_id, request.user_uniq, for_update=True) |
|
91 |
action = req.keys()[0] |
|
92 |
try: |
|
93 |
f = NETWORK_ACTIONS[action] |
|
94 |
except KeyError: |
|
95 |
raise faults.BadRequest("Action %s not supported." % action) |
|
96 |
action_args = req[action] |
|
97 |
if not isinstance(action_args, dict): |
|
98 |
raise faults.BadRequest("Invalid argument.") |
|
99 |
|
|
100 |
return f(request, network, action_args) |
|
101 |
|
|
102 |
|
|
84 | 103 |
@api.api_method(http_method='GET', user_required=True, logger=log) |
85 | 104 |
def list_networks(request, detail=True): |
86 | 105 |
log.debug('list_networks detail=%s', detail) |
... | ... | |
196 | 215 |
return d |
197 | 216 |
|
198 | 217 |
|
218 |
@transaction.commit_on_success |
|
219 |
def reassign_network(request, network, args): |
|
220 |
project = args.get("project") |
|
221 |
if project is None: |
|
222 |
raise faults.BadRequest("Missing 'project' attribute.") |
|
223 |
networks.reassign(network, project) |
|
224 |
return HttpResponse(status=200) |
|
225 |
|
|
226 |
|
|
227 |
NETWORK_ACTIONS = { |
|
228 |
"reassign": reassign_network, |
|
229 |
} |
|
230 |
|
|
231 |
|
|
199 | 232 |
def render_network(request, networkdict, status=200): |
200 | 233 |
if request.serialization == 'xml': |
201 | 234 |
data = render_to_string('network.xml', {'network': networkdict}) |
b/snf-cyclades-app/synnefo/api/servers.py | ||
---|---|---|
479 | 479 |
|
480 | 480 |
|
481 | 481 |
# additional server actions |
482 |
ARBITRARY_ACTIONS = ['console', 'firewallProfile'] |
|
482 |
ARBITRARY_ACTIONS = ['console', 'firewallProfile', 'reassign']
|
|
483 | 483 |
|
484 | 484 |
|
485 | 485 |
def key_to_action(key): |
... | ... | |
878 | 878 |
raise faults.NotImplemented('Resize not supported.') |
879 | 879 |
|
880 | 880 |
|
881 |
@server_action('reassign') |
|
882 |
def reassign(request, vm, args): |
|
883 |
project = args.get("project") |
|
884 |
if project is None: |
|
885 |
raise faults.BadRequest("Missing 'project' attribute.") |
|
886 |
servers.reassign(vm, project) |
|
887 |
return HttpResponse(status=200) |
|
888 |
|
|
889 |
|
|
881 | 890 |
@network_action('add') |
882 | 891 |
@transaction.commit_on_success |
883 | 892 |
def add(request, net, args): |
b/snf-cyclades-app/synnefo/logic/ips.py | ||
---|---|---|
230 | 230 |
log.info("Deleted floating IP '%s' of user '%s", floating_ip, |
231 | 231 |
floating_ip.userid) |
232 | 232 |
floating_ip.delete() |
233 |
|
|
234 |
|
|
235 |
@transaction.commit_on_success |
|
236 |
def reassign_floating_ip(floating_ip, project): |
|
237 |
action_fields = {"to_project": project, |
|
238 |
"from_project": floating_ip.project} |
|
239 |
floating_ip.project = project |
|
240 |
floating_ip.save() |
|
241 |
quotas.issue_and_accept_commission(floating_ip, action="REASSIGN", |
|
242 |
action_fields=action_fields) |
b/snf-cyclades-app/synnefo/logic/networks.py | ||
---|---|---|
174 | 174 |
# If network does not exist in any backend, update the network state |
175 | 175 |
backend_mod.update_network_state(network) |
176 | 176 |
return network |
177 |
|
|
178 |
|
|
179 |
@network_command("REASSIGN") |
|
180 |
def reassign(network, project): |
|
181 |
action_fields = {"to_project": project, "from_project": network.project} |
|
182 |
network.project = project |
|
183 |
network.save() |
|
184 |
quotas.issue_and_accept_commission(network, action="REASSIGN", |
|
185 |
action_fields=action_fields) |
|
186 |
return network |
b/snf-cyclades-app/synnefo/logic/servers.py | ||
---|---|---|
333 | 333 |
return backend.resize_instance(vm, vcpus=flavor.cpu, memory=flavor.ram) |
334 | 334 |
|
335 | 335 |
|
336 |
@transaction.commit_on_success |
|
337 |
def reassign(vm, project): |
|
338 |
action_fields = {"to_project": project, "from_project": vm.project} |
|
339 |
vm.project = project |
|
340 |
vm.save() |
|
341 |
quotas.issue_and_accept_commission(vm, action="REASSIGN", |
|
342 |
action_fields=action_fields) |
|
343 |
|
|
344 |
|
|
336 | 345 |
@server_command("SET_FIREWALL_PROFILE") |
337 | 346 |
def set_firewall_profile(vm, profile, nic): |
338 | 347 |
log.info("Setting VM %s, NIC %s, firewall %s", vm, nic, profile) |
b/snf-cyclades-app/synnefo/quotas/__init__.py | ||
---|---|---|
131 | 131 |
source = resource.project |
132 | 132 |
|
133 | 133 |
qh = Quotaholder.get() |
134 |
if True: # placeholder |
|
134 |
if action == "REASSIGN": |
|
135 |
try: |
|
136 |
from_project = action_fields["from_project"] |
|
137 |
to_project = action_fields["to_project"] |
|
138 |
except KeyError: |
|
139 |
raise Exception("Missing project attribute.") |
|
140 |
|
|
141 |
projects = [from_project, to_project] |
|
142 |
with AstakosClientExceptionHandler(user=user, projects=projects): |
|
143 |
serial = qh.issue_resource_reassignment(user, |
|
144 |
from_project, to_project, |
|
145 |
provisions, name=name, |
|
146 |
force=force, |
|
147 |
auto_accept=auto_accept) |
|
148 |
else: |
|
135 | 149 |
with AstakosClientExceptionHandler(user=user, projects=[source]): |
136 | 150 |
serial = qh.issue_one_commission(user, source, |
137 | 151 |
provisions, name=name, |
... | ... | |
352 | 366 |
ram = beparams.get("maxmem", flavor.ram) |
353 | 367 |
return {"cyclades.total_cpu": cpu - flavor.cpu, |
354 | 368 |
"cyclades.total_ram": 1048576 * (ram - flavor.ram)} |
369 |
elif action == "REASSIGN": |
|
370 |
if resource.operstate in ["STARTED", "BUILD", "ERROR"]: |
|
371 |
resources.update(online_resources) |
|
372 |
return resources |
|
355 | 373 |
else: |
356 | 374 |
#["CONNECT", "DISCONNECT", "SET_FIREWALL_PROFILE"]: |
357 | 375 |
return None |
... | ... | |
361 | 379 |
return resources |
362 | 380 |
elif action == "DESTROY": |
363 | 381 |
return reverse_quantities(resources) |
382 |
elif action == "REASSIGN": |
|
383 |
return resources |
|
364 | 384 |
elif isinstance(resource, IPAddress): |
365 | 385 |
if resource.floating_ip: |
366 | 386 |
resources = {"cyclades.floating_ip": 1} |
... | ... | |
368 | 388 |
return resources |
369 | 389 |
elif action == "DESTROY": |
370 | 390 |
return reverse_quantities(resources) |
391 |
elif action == "REASSIGN": |
|
392 |
return resources |
|
371 | 393 |
else: |
372 | 394 |
return None |
373 | 395 |
|
Also available in: Unified diff