Manually added OpenStack API code
[osm/vim-emu.git] / src / emuvim / api / openstack / openstack_dummies / nova_dummy_api.py
1 from flask_restful import Resource
2 from flask import Response, request
3 from emuvim.api.openstack.openstack_dummies.base_openstack_dummy import BaseOpenstackDummy
4 import logging
5 import json
6 import uuid
7 from mininet.link import Link
8
9
10 class NovaDummyApi(BaseOpenstackDummy):
11 def __init__(self, in_ip, in_port, compute):
12 super(NovaDummyApi, self).__init__(in_ip, in_port)
13 self.compute = compute
14
15 self.api.add_resource(NovaVersionsList, "/",
16 resource_class_kwargs={'api': self})
17 self.api.add_resource(Shutdown, "/shutdown")
18 self.api.add_resource(NovaVersionShow, "/v2.1/<id>",
19 resource_class_kwargs={'api': self})
20 self.api.add_resource(NovaListServersApi, "/v2.1/<id>/servers",
21 resource_class_kwargs={'api': self})
22 self.api.add_resource(NovaListServersAndPortsApi, "/v2.1/<id>/servers/andPorts",
23 resource_class_kwargs={'api': self})
24 self.api.add_resource(NovaListServersDetailed, "/v2.1/<id>/servers/detail",
25 resource_class_kwargs={'api': self})
26 self.api.add_resource(NovaShowServerDetails, "/v2.1/<id>/servers/<serverid>",
27 resource_class_kwargs={'api': self})
28 self.api.add_resource(NovaInterfaceToServer, "/v2.1/<id>/servers/<serverid>/os-interface",
29 resource_class_kwargs={'api': self})
30 self.api.add_resource(NovaShowAndDeleteInterfaceAtServer, "/v2.1/<id>/servers/<serverid>/os-interface/<port_id>",
31 resource_class_kwargs={'api': self})
32 self.api.add_resource(NovaListFlavors, "/v2.1/<id>/flavors", "/v2/<id>/flavors",
33 resource_class_kwargs={'api': self})
34 self.api.add_resource(NovaListFlavorsDetails, "/v2.1/<id>/flavors/detail", "/v2/<id>/flavors/detail",
35 resource_class_kwargs={'api': self})
36 self.api.add_resource(NovaListFlavorById, "/v2.1/<id>/flavors/<flavorid>", "/v2/<id>/flavors/<flavorid>",
37 resource_class_kwargs={'api': self})
38 self.api.add_resource(NovaListImages, "/v2.1/<id>/images",
39 resource_class_kwargs={'api': self})
40 self.api.add_resource(NovaListImagesDetails, "/v2.1/<id>/images/detail",
41 resource_class_kwargs={'api': self})
42 self.api.add_resource(NovaListImageById, "/v2.1/<id>/images/<imageid>",
43 resource_class_kwargs={'api': self})
44
45 def _start_flask(self):
46 logging.info("Starting %s endpoint @ http://%s:%d" % ("NovaDummyApi", self.ip, self.port))
47 # add some flavors for good measure
48 self.compute.add_flavor('m1.tiny', 1, 512, "MB", 1, "GB")
49 self.compute.add_flavor('m1.nano', 1, 64, "MB", 0, "GB")
50 self.compute.add_flavor('m1.micro', 1, 128, "MB", 0, "GB")
51 self.compute.add_flavor('m1.small', 1, 1024, "MB", 2, "GB")
52 if self.app is not None:
53 self.app.before_request(self.dump_playbook)
54 self.app.run(self.ip, self.port, debug=True, use_reloader=False)
55
56
57 class Shutdown(Resource):
58 """
59 A get request to /shutdown will shut down this endpoint.
60 """
61
62 def get(self):
63 logging.debug(("%s is beeing shut doen") % (__name__))
64 func = request.environ.get('werkzeug.server.shutdown')
65 if func is None:
66 raise RuntimeError('Not running with the Werkzeug Server')
67 func()
68
69
70 class NovaVersionsList(Resource):
71 def __init__(self, api):
72 self.api = api
73
74 def get(self):
75 """
76 Lists API versions.
77
78 :return: Returns a json with API versions.
79 :rtype: :class:`flask.response`
80 """
81 logging.debug("API CALL: %s GET" % str(self.__class__.__name__))
82 try:
83 resp = """
84 {
85 "versions": [
86 {
87 "id": "v2.1",
88 "links": [
89 {
90 "href": "http://%s:%d/v2.1/",
91 "rel": "self"
92 }
93 ],
94 "status": "CURRENT",
95 "version": "2.38",
96 "min_version": "2.1",
97 "updated": "2013-07-23T11:33:21Z"
98 }
99 ]
100 }
101 """ % (self.api.ip, self.api.port)
102
103 response = Response(resp, status=200, mimetype="application/json")
104 response.headers['Access-Control-Allow-Origin'] = '*'
105 return response
106
107 except Exception as ex:
108 logging.exception(u"%s: Could not show list of versions." % __name__)
109 return ex.message, 500
110
111
112 class NovaVersionShow(Resource):
113 def __init__(self, api):
114 self.api = api
115
116 def get(self, id):
117 """
118 Returns API details.
119
120 :param id:
121 :type id: ``str``
122 :return: Returns a json with API details.
123 :rtype: :class:`flask.response`
124 """
125 logging.debug("API CALL: %s GET" % str(self.__class__.__name__))
126
127 try:
128 resp = """
129 {
130 "version": {
131 "id": "v2.1",
132 "links": [
133 {
134 "href": "http://%s:%d/v2.1/",
135 "rel": "self"
136 },
137 {
138 "href": "http://docs.openstack.org/",
139 "rel": "describedby",
140 "type": "text/html"
141 }
142 ],
143 "media-types": [
144 {
145 "base": "application/json",
146 "type": "application/vnd.openstack.compute+json;version=2.1"
147 }
148 ],
149 "status": "CURRENT",
150 "version": "2.38",
151 "min_version": "2.1",
152 "updated": "2013-07-23T11:33:21Z"
153 }
154 }
155 """ % (self.api.ip, self.api.port)
156
157 response = Response(resp, status=200, mimetype="application/json")
158 response.headers['Access-Control-Allow-Origin'] = '*'
159 return response
160
161 except Exception as ex:
162 logging.exception(u"%s: Could not show list of versions." % __name__)
163 return ex.message, 500
164
165
166 class NovaListServersApi(Resource):
167 def __init__(self, api):
168 self.api = api
169
170 def get(self, id):
171 """
172 Creates a list with all running servers and their detailed information.
173
174 :param id: Used to create a individual link to quarry further information.
175 :type id: ``str``
176 :return: Returns a json response with a dictionary that contains the server information.
177 :rtype: :class:`flask.response`
178 """
179 logging.debug("API CALL: %s GET" % str(self.__class__.__name__))
180
181 try:
182 resp = dict()
183 resp['servers'] = list()
184 for server in self.api.compute.computeUnits.values():
185 s = server.create_server_dict(self.api.compute)
186 s['links'] = [{'href': "http://%s:%d/v2.1/%s/servers/%s" % (self.api.ip,
187 self.api.port,
188 id,
189 server.id)}]
190
191 resp['servers'].append(s)
192
193 response = Response(json.dumps(resp), status=200, mimetype="application/json")
194 response.headers['Access-Control-Allow-Origin'] = '*'
195 return response
196
197 except Exception as ex:
198 logging.exception(u"%s: Could not retrieve the list of servers." % __name__)
199 return ex.message, 500
200
201 def post(self, id):
202 """
203 Creates a server instance.
204
205 :param id: tenant id, we ignore this most of the time
206 :type id: ``str``
207 :return: Returns a flask response, with detailed information about the just created server.
208 :rtype: :class:`flask.response`
209 """
210 logging.debug("API CALL: %s POST" % str(self.__class__.__name__))
211 try:
212 server_dict = json.loads(request.data)['server']
213 networks = server_dict.get('networks', None)
214 name = str(self.api.compute.dc.label) + "_man_" + server_dict["name"][0:12]
215
216 if self.api.compute.find_server_by_name_or_id(name) is not None:
217 return Response("Server with name %s already exists." % name, status=409)
218 # TODO: not finished!
219 resp = dict()
220
221 server = self.api.compute.create_server(name)
222 server.full_name = str(self.api.compute.dc.label) + "_man_" + server_dict["name"]
223 server.template_name = server_dict["name"]
224
225 for flavor in self.api.compute.flavors.values():
226 if flavor.id == server_dict.get('flavorRef', ''):
227 server.flavor = flavor.name
228 for image in self.api.compute.images.values():
229 if image.id in server_dict['imageRef']:
230 server.image = image.name
231
232 if networks is not None:
233 for net in networks:
234 port = self.api.compute.find_port_by_name_or_id(net.get('port', ""))
235 if port is not None:
236 server.port_names.append(port.name)
237 else:
238 return Response("Currently only networking by port is supported.", status=400)
239
240 self.api.compute._start_compute(server)
241
242 response = NovaShowServerDetails(self.api).get(id, server.id)
243 response.headers['Access-Control-Allow-Origin'] = '*'
244 return response
245
246 except Exception as ex:
247 logging.exception(u"%s: Could not create the server." % __name__)
248 return ex.message, 500
249
250
251 class NovaListServersAndPortsApi(Resource):
252 def __init__(self, api):
253 self.api = api
254
255 def get(self, id):
256 """
257 Creates a list with all running servers and their detailed information. This function also presents all
258 port information of each server.
259
260 :param id: Used to create a individual link to quarry further information.
261 :type id: ``str``
262 :return: Returns a json response with a dictionary that contains the server information.
263 :rtype: :class:`flask.response`
264 """
265 logging.debug("API CALL: %s GET" % str(self.__class__.__name__))
266
267 try:
268 resp = dict()
269 resp['servers'] = list()
270 for server in self.api.compute.computeUnits.values():
271 s = server.create_server_dict(self.api.compute)
272 s['links'] = [{'href': "http://%s:%d/v2.1/%s/servers/%s" % (self.api.ip,
273 self.api.port,
274 id,
275 server.id)}]
276
277 s['ports'] = list()
278 for port_name in server.port_names:
279 port = self.api.compute.find_port_by_name_or_id(port_name)
280 if port is None:
281 continue
282
283 tmp = port.create_port_dict(self.api.compute)
284 tmp['intf_name'] = port.intf_name
285 s['ports'].append(tmp)
286
287 resp['servers'].append(s)
288
289 response = Response(json.dumps(resp), status=200, mimetype="application/json")
290 response.headers['Access-Control-Allow-Origin'] = '*'
291 return response
292
293 except Exception as ex:
294 logging.exception(u"%s: Could not retrieve the list of servers." % __name__)
295 return ex.message, 500
296
297
298 class NovaListServersDetailed(Resource):
299 def __init__(self, api):
300 self.api = api
301
302 def get(self, id):
303 """
304 As List Servers, it lists all running servers and their details but furthermore it also states the
305 used flavor and the server image.
306
307 :param id: tenant id, used for the 'href' link.
308 :type id: ``str``
309 :return: Returns a flask response, with detailed information aboit the servers and their flavor and image.
310 :rtype: :class:`flask.response`
311 """
312 logging.debug("API CALL: %s GET" % str(self.__class__.__name__))
313
314 try:
315 resp = {"servers": list()}
316 for server in self.api.compute.computeUnits.values():
317 s = server.create_server_dict(self.api.compute)
318 s['links'] = [{'href': "http://%s:%d/v2.1/%s/servers/%s" % (self.api.ip,
319 self.api.port,
320 id,
321 server.id)}]
322 flavor = self.api.compute.flavors[server.flavor]
323 s['flavor'] = {
324 "id": flavor.id,
325 "links": [
326 {
327 "href": "http://%s:%d/v2.1/%s/flavors/%s" % (self.api.ip,
328 self.api.port,
329 id,
330 flavor.id),
331 "rel": "bookmark"
332 }
333 ]
334 }
335 image = self.api.compute.images[server.image]
336 s['image'] = {
337 "id": image.id,
338 "links": [
339 {
340 "href": "http://%s:%d/v2.1/%s/images/%s" % (self.api.ip,
341 self.api.port,
342 id,
343 image.id),
344 "rel": "bookmark"
345 }
346 ]
347 }
348
349 resp['servers'].append(s)
350
351 response = Response(json.dumps(resp), status=200, mimetype="application/json")
352 response.headers['Access-Control-Allow-Origin'] = '*'
353 return response
354
355 except Exception as ex:
356 logging.exception(u"%s: Could not retrieve the list of servers." % __name__)
357 return ex.message, 500
358
359
360 class NovaListFlavors(Resource):
361 def __init__(self, api):
362 self.api = api
363
364 def get(self, id):
365 """
366 Lists all available flavors.
367
368 :param id: tenant id, used for the 'href' link
369 :type id: ``str``
370 :return: Returns a flask response with a list of all flavors.
371 :rtype: :class:`flask.response`
372 """
373 logging.debug("API CALL: %s GET" % str(self.__class__.__name__))
374 try:
375 resp = dict()
376 resp['flavors'] = list()
377 for flavor in self.api.compute.flavors.values():
378 f = flavor.__dict__.copy()
379 f['id'] = flavor.id
380 f['name'] = flavor.name
381 f['links'] = [{'href': "http://%s:%d/v2.1/%s/flavors/%s" % (self.api.ip,
382 self.api.port,
383 id,
384 flavor.id)}]
385 resp['flavors'].append(f)
386
387 response = Response(json.dumps(resp), status=200, mimetype="application/json")
388 response.headers['Access-Control-Allow-Origin'] = '*'
389 return response
390
391 except Exception as ex:
392 logging.exception(u"%s: Could not retrieve the list of servers." % __name__)
393 return ex.message, 500
394
395 def post(self, id):
396 logging.debug("API CALL: %s POST" % str(self.__class__.__name__))
397 data = json.loads(request.data).get("flavor")
398 logging.warning("Create Flavor: %s" % str(data))
399 # add to internal dict
400 f = self.api.compute.add_flavor(
401 data.get("name"),
402 data.get("vcpus"),
403 data.get("ram"), "MB",
404 data.get("disk"), "GB")
405 # create response based on incoming data
406 data["id"] = f.id
407 data["links"] = [{'href': "http://%s:%d/v2.1/%s/flavors/%s" % (self.api.ip,
408 self.api.port,
409 id,
410 f.id)}]
411 resp = {"flavor": data}
412 return Response(json.dumps(resp), status=200, mimetype="application/json")
413
414
415 class NovaListFlavorsDetails(Resource):
416 def __init__(self, api):
417 self.api = api
418
419 def get(self, id):
420 """
421 Lists all flavors with additional information like ram and disk space.
422
423 :param id: tenant id, used for the 'href' link
424 :type id: ``str``
425 :return: Returns a flask response with a list of all flavors with additional information.
426 :rtype: :class:`flask.response`
427 """
428 logging.debug("API CALL: %s GET" % str(self.__class__.__name__))
429 try:
430 resp = dict()
431 resp['flavors'] = list()
432 for flavor in self.api.compute.flavors.values():
433 # use the class dict. it should work fine
434 # but use a copy so we don't modifiy the original
435 f = flavor.__dict__.copy()
436 # add additional expected stuff stay openstack compatible
437 f['links'] = [{'href': "http://%s:%d/v2.1/%s/flavors/%s" % (self.api.ip,
438 self.api.port,
439 id,
440 flavor.id)}]
441 f['OS-FLV-DISABLED:disabled'] = False
442 f['OS-FLV-EXT-DATA:ephemeral'] = 0
443 f['os-flavor-access:is_public'] = True
444 f['ram'] = flavor.memory
445 f['vcpus'] = flavor.cpu
446 f['swap'] = 0
447 f['disk'] = flavor.storage
448 f['rxtx_factor'] = 1.0
449 resp['flavors'].append(f)
450
451 response = Response(json.dumps(resp), status=200, mimetype="application/json")
452 response.headers['Access-Control-Allow-Origin'] = '*'
453 return response
454
455 except Exception as ex:
456 logging.exception(u"%s: Could not retrieve the list of servers." % __name__)
457 return ex.message, 500
458
459 def post(self, id):
460 logging.debug("API CALL: %s POST" % str(self.__class__.__name__))
461 data = json.loads(request.data).get("flavor")
462 logging.warning("Create Flavor: %s" % str(data))
463 # add to internal dict
464 f = self.api.compute.add_flavor(
465 data.get("name"),
466 data.get("vcpus"),
467 data.get("ram"), "MB",
468 data.get("disk"), "GB")
469 # create response based on incoming data
470 data["id"] = f.id
471 data["links"] = [{'href': "http://%s:%d/v2.1/%s/flavors/%s" % (self.api.ip,
472 self.api.port,
473 id,
474 f.id)}]
475 resp = {"flavor": data}
476 return Response(json.dumps(resp), status=200, mimetype="application/json")
477
478
479 class NovaListFlavorById(Resource):
480 def __init__(self, api):
481 self.api = api
482
483 def get(self, id, flavorid):
484 """
485 Returns details about one flavor.
486
487 :param id: tenant id, used for the 'href' link
488 :type id: ``str``
489 :param flavorid: Represents the flavor.
490 :type flavorid: ``str``
491 :return: Returns a flask response with detailed information about the flavor.
492 :rtype: :class:`flask.response`
493 """
494 logging.debug("API CALL: %s GET" % str(self.__class__.__name__))
495 try:
496 resp = dict()
497 resp['flavor'] = dict()
498 flavor = self.api.compute.flavors.get(flavorid, None)
499 if flavor is None:
500 for f in self.api.compute.flavors.values():
501 if f.id == flavorid:
502 flavor = f
503 break
504 resp['flavor']['id'] = flavor.id
505 resp['flavor']['name'] = flavor.name
506 resp['flavor']['links'] = [{'href': "http://%s:%d/v2.1/%s/flavors/%s" % (self.api.ip,
507 self.api.port,
508 id,
509 flavor.id)}]
510 response = Response(json.dumps(resp), status=200, mimetype="application/json")
511 response.headers['Access-Control-Allow-Origin'] = '*'
512 return response
513
514 except Exception as ex:
515 logging.exception(u"%s: Could not retrieve flavor with id %s" % (__name__, flavorid))
516 return ex.message, 500
517
518
519 class NovaListImages(Resource):
520 def __init__(self, api):
521 self.api = api
522
523 def get(self, id):
524 """
525 Creates a list of all usable images.
526
527 :param id: tenant id, used for the 'href' link
528 :type id: ``str``
529 :return: Returns a flask response with a list of available images.
530 :rtype: :class:`flask.response`
531 """
532 logging.debug("API CALL: %s GET" % str(self.__class__.__name__))
533 try:
534 resp = dict()
535 resp['images'] = list()
536 for image in self.api.compute.images.values():
537 f = dict()
538 f['id'] = image.id
539 f['name'] = str(image.name).replace(":latest", "")
540 f['links'] = [{'href': "http://%s:%d/v2.1/%s/images/%s" % (self.api.ip,
541 self.api.port,
542 id,
543 image.id)}]
544 resp['images'].append(f)
545 response = Response(json.dumps(resp), status=200, mimetype="application/json")
546 response.headers['Access-Control-Allow-Origin'] = '*'
547 return response
548
549 except Exception as ex:
550 logging.exception(u"%s: Could not retrieve the list of images." % __name__)
551 return ex.message, 500
552
553
554 class NovaListImagesDetails(Resource):
555 def __init__(self, api):
556 self.api = api
557
558 def get(self, id):
559 """
560 As List Images but with additional metadata.
561
562 :param id: tenant id, used for the 'href' link
563 :type id: ``str``
564 :return: Returns a flask response with a list of images and their metadata.
565 :rtype: :class:`flask.response`
566 """
567 logging.debug("API CALL: %s GET" % str(self.__class__.__name__))
568 try:
569 resp = dict()
570 resp['images'] = list()
571 for image in self.api.compute.images.values():
572 # use the class dict. it should work fine
573 # but use a copy so we don't modifiy the original
574 f = image.__dict__.copy()
575 # add additional expected stuff stay openstack compatible
576 f['name'] = str(image.name).replace(":latest", "")
577 f['links'] = [{'href': "http://%s:%d/v2.1/%s/images/%s" % (self.api.ip,
578 self.api.port,
579 id,
580 image.id)}]
581 f['metadata'] = {
582 "architecture": "x86_64",
583 "auto_disk_config": "True",
584 "kernel_id": "nokernel",
585 "ramdisk_id": "nokernel"
586 }
587 resp['images'].append(f)
588
589 response = Response(json.dumps(resp), status=200, mimetype="application/json")
590 response.headers['Access-Control-Allow-Origin'] = '*'
591 return response
592
593 except Exception as ex:
594 logging.exception(u"%s: Could not retrieve the list of images." % __name__)
595 return ex.message, 500
596
597
598 class NovaListImageById(Resource):
599 def __init__(self, api):
600 self.api = api
601
602 def get(self, id, imageid):
603 """
604 Gets an image by id from the emulator with openstack nova compliant return values.
605
606 :param id: tenantid, we ignore this most of the time
607 :type id: ``str``
608 :param imageid: id of the image. If it is 1 the dummy CREATE-IMAGE is returned
609 :type imageid: ``str``
610 :return: Returns a flask response with the information about one image.
611 :rtype: :class:`flask.response`
612 """
613 logging.debug("API CALL: %s GET" % str(self.__class__.__name__))
614 try:
615 resp = dict()
616 i = resp['image'] = dict()
617 for image in self.api.compute.images.values():
618 if image.id == imageid or image.name == imageid:
619 i['id'] = image.id
620 i['name'] = image.name
621
622 return Response(json.dumps(resp), status=200, mimetype="application/json")
623
624 response = Response("Image with id or name %s does not exists." % imageid, status=404)
625 response.headers['Access-Control-Allow-Origin'] = '*'
626 return response
627
628 except Exception as ex:
629 logging.exception(u"%s: Could not retrieve image with id %s." % (__name__, imageid))
630 return ex.message, 500
631
632
633 class NovaShowServerDetails(Resource):
634 def __init__(self, api):
635 self.api = api
636
637 def get(self, id, serverid):
638 """
639 Returns detailed information about the specified server.
640
641 :param id: tenant id, used for the 'href' link
642 :type id: ``str``
643 :param serverid: Specifies the requested server.
644 :type serverid: ``str``
645 :return: Returns a flask response with details about the server.
646 :rtype: :class:`flask.response`
647 """
648 logging.debug("API CALL: %s GET" % str(self.__class__.__name__))
649 try:
650 server = self.api.compute.find_server_by_name_or_id(serverid)
651 if server is None:
652 return Response("Server with id or name %s does not exists." % serverid, status=404)
653 s = server.create_server_dict()
654 s['links'] = [{'href': "http://%s:%d/v2.1/%s/servers/%s" % (self.api.ip,
655 self.api.port,
656 id,
657 server.id)}]
658
659 flavor = self.api.compute.flavors[server.flavor]
660 s['flavor'] = {
661 "id": flavor.id,
662 "links": [
663 {
664 "href": "http://%s:%d/v2.1/%s/flavors/%s" % (self.api.ip,
665 self.api.port,
666 id,
667 flavor.id),
668 "rel": "bookmark"
669 }
670 ]
671 }
672 image = self.api.compute.images[server.image]
673 s['image'] = {
674 "id": image.id,
675 "links": [
676 {
677 "href": "http://%s:%d/v2.1/%s/images/%s" % (self.api.ip,
678 self.api.port,
679 id,
680 image.id),
681 "rel": "bookmark"
682 }
683 ]
684 }
685
686 response = Response(json.dumps({'server': s}), status=200, mimetype="application/json")
687 response.headers['Access-Control-Allow-Origin'] = '*'
688 return response
689
690 except Exception as ex:
691 logging.exception(u"%s: Could not retrieve the server details." % __name__)
692 return ex.message, 500
693
694 def delete(self, id, serverid):
695 """
696 Delete a server instance.
697
698 :param id: tenant id, we ignore this most of the time
699 :type id: ``str``
700 :param serverid: The UUID of the server
701 :type serverid: ``str``
702 :return: Returns 200 if everything is fine.
703 :rtype: :class:`flask.response`
704 """
705 logging.debug("API CALL: %s POST" % str(self.__class__.__name__))
706 try:
707 server = self.api.compute.find_server_by_name_or_id(serverid)
708 if server is None:
709 return Response('Could not find server.', status=404, mimetype="application/json")
710
711 self.api.compute.stop_compute(server)
712
713 response = Response('Server deleted.', status=204, mimetype="application/json")
714 response.headers['Access-Control-Allow-Origin'] = '*'
715 return response
716
717 except Exception as ex:
718 logging.exception(u"%s: Could not create the server." % __name__)
719 return ex.message, 500
720
721
722 class NovaInterfaceToServer(Resource):
723 def __init__(self, api):
724 self.api = api
725
726 def post(self, id, serverid):
727 """
728 Add an interface to the specified server.
729
730 :param id: tenant id, we ignore this most of the time
731 :type id: ``str``
732 :param serverid: Specifies the server.
733 :type serverid: ``str``
734 :return: Returns a flask response with information about the attached interface.
735 :rtype: :class:`flask.response`
736 """
737 logging.debug("API CALL: %s GET" % str(self.__class__.__name__))
738 try:
739 server = self.api.compute.find_server_by_name_or_id(serverid)
740 if server is None:
741 return Response("Server with id or name %s does not exists." % serverid, status=404)
742
743 if server.emulator_compute is None:
744 logging.error("The targeted container does not exist.")
745 return Response("The targeted container of %s does not exist." % serverid, status=404)
746 data = json.loads(request.data).get("interfaceAttachment")
747 resp = dict()
748 port = data.get("port_id", None)
749 net = data.get("net_id", None)
750 dc = self.api.compute.dc
751 network_dict = dict()
752 network = None
753
754 if net is not None and port is not None:
755 port = self.api.compute.find_port_by_name_or_id(port)
756 network = self.api.compute.find_network_by_name_or_id(net)
757 network_dict['id'] = port.intf_name
758 network_dict['ip'] = port.ip_address
759 network_dict[network_dict['id']] = network.name
760 elif net is not None:
761 network = self.api.compute.find_network_by_name_or_id(net)
762 if network is None:
763 return Response("Network with id or name %s does not exists." % net, status=404)
764 port = self.api.compute.create_port("port:cp%s:fl:%s" %
765 (len(self.api.compute.ports), str(uuid.uuid4())))
766
767 port.net_name = network.name
768 port.ip_address = network.get_new_ip_address(port.name)
769 network_dict['id'] = port.intf_name
770 network_dict['ip'] = port.ip_address
771 network_dict[network_dict['id']] = network.name
772 elif port is not None:
773 port = self.api.compute.find_port_by_name_or_id(port)
774 network_dict['id'] = port.intf_name
775 network_dict['ip'] = port.ip_address
776 network = self.api.compute.find_network_by_name_or_id(port.net_name)
777 network_dict[network_dict['id']] = network.name
778 else:
779 raise Exception("You can only attach interfaces by port or network at the moment")
780
781 if network == self.api.manage.floating_network:
782 dc.net.addLink(server.emulator_compute, self.api.manage.floating_switch,
783 params1=network_dict, cls=Link, intfName1=port.intf_name)
784 else:
785 dc.net.addLink(server.emulator_compute, dc.switch,
786 params1=network_dict, cls=Link, intfName1=port.intf_name)
787 resp["port_state"] = "ACTIVE"
788 resp["port_id"] = port.id
789 resp["net_id"] = self.api.compute.find_network_by_name_or_id(port.net_name).id
790 resp["mac_addr"] = port.mac_address
791 resp["fixed_ips"] = list()
792 fixed_ips = dict()
793 fixed_ips["ip_address"] = port.ip_address
794 fixed_ips["subnet_id"] = network.subnet_name
795 resp["fixed_ips"].append(fixed_ips)
796 response = Response(json.dumps({"interfaceAttachment": resp}), status=202, mimetype="application/json")
797 response.headers['Access-Control-Allow-Origin'] = '*'
798 return response
799
800 except Exception as ex:
801 logging.exception(u"%s: Could not add interface to the server." % __name__)
802 return ex.message, 500
803
804
805 class NovaShowAndDeleteInterfaceAtServer(Resource):
806 def __init__(self, api):
807 self.api = api
808
809 def delete(self, id, serverid, port_id):
810 """
811 Deletes an existing interface.
812
813 :param id: tenant id, we ignore this most of the time
814 :type id: ``str``
815 :param serverid: Specifies the server, where the interface will be deleted.
816 :type serverid: ``str``
817 :param port_id: Specifies the port of the interface.
818 :type port_id: ``str``
819 :return: Returns a flask response with 202 if everything worked out. Otherwise it will return 404 and an
820 error message.
821 :rtype: :class:`flask.response`
822 """
823 logging.debug("API CALL: %s GET" % str(self.__class__.__name__))
824 try:
825 server = self.api.compute.find_server_by_name_or_id(serverid)
826 if server is None:
827 return Response("Server with id or name %s does not exists." % serverid, status=404)
828 port = self.api.compute.find_port_by_name_or_id(port_id)
829 if port is None:
830 return Response("Port with id or name %s does not exists." % port_id, status=404)
831
832 for link in self.api.compute.dc.net.links:
833 if str(link.intf1) == port.intf_name and \
834 str(link.intf1.ip) == port.ip_address.split('/')[0]:
835 self.api.compute.dc.net.removeLink(link)
836 break
837
838 response = Response("", status=202, mimetype="application/json")
839 response.headers['Access-Control-Allow-Origin'] = '*'
840 return response
841
842 except Exception as ex:
843 logging.exception(u"%s: Could not detach interface from the server." % __name__)
844 return ex.message, 500