Commit 89f43b4b by Fukász Rómeó Ervin

refactor occi api views and classes

parent 5a4b3e24
......@@ -24,8 +24,25 @@ import json
# kikapcsoljuk a figyelmezteteseket
# urllib3.disable_warnings()
def dumps(*args, **kwargs):
try:
return json.dumps(*args, **kwargs)
except Exception as e:
print(e)
return {}
def loads(*args, **kwargs):
try:
return json.loads(*args, **kwargs)
except Exception as e:
print(e)
return {}
# A szerver base url-je es a felhasznalo adatai
server = "https://vm.ik.bme.hu:15766/"
server = "https://localhost/"
username = "admin"
password = "retekretek"
loginData = {"username": username, "password": password}
......@@ -42,8 +59,8 @@ with requests.Session() as session:
print("----------")
print("status_code: " + str(req.status_code))
print
print(json.dumps(json.loads(req.text), sort_keys=True,
indent=4, separators=(",", ": ")))
print(dumps(loads(req.text), sort_keys=True,
indent=4, separators=(",", ": ")))
print
# Bejelentkezes
......@@ -52,13 +69,58 @@ with requests.Session() as session:
# a cookie-ban
headers["X-CSRFToken"] = req.cookies['csrftoken']
req = session.post(server + "occi/login/", verify=False,
data=json.dumps(loginData), headers=headers)
data=dumps(loginData), headers=headers)
print("login")
print("-----")
print("status_code: " + str(req.status_code))
print
print(json.dumps(json.loads(req.text), sort_keys=True,
indent=4, separators=(",", ": ")))
print(dumps(loads(req.text), sort_keys=True,
indent=4, separators=(",", ": ")))
print
headers["X-CSRFToken"] = req.cookies['csrftoken']
req = session.get(server + "occi/token/", verify=False,
headers=headers)
print("token")
print("-----")
print("status_code: " + str(req.status_code))
print
print(dumps(loads(req.text), sort_keys=True,
indent=4, separators=(",", ": ")))
token = req.json()["token"]
req = session.get(server + "occi/test/?token=" + token, verify=False,
headers=headers)
print("token-use")
print("---------")
print(server + "occi/test/?token=" + token)
print("status_code: " + str(req.status_code))
print
print(dumps(loads(req.text), sort_keys=True,
indent=4, separators=(",", ": ")))
req = session.get(server + "occi/test/?token=asdasdasd" + token, verify=False,
headers=headers)
print("token-use")
print("---------")
print(server + "occi/test/?token=" + token)
print("status_code: " + str(req.status_code))
print
print(dumps(loads(req.text), sort_keys=True,
indent=4, separators=(",", ": ")))
exit()
# storage creation wrong
headers["X-CSRFToken"] = req.cookies['csrftoken']
req = session.put(server + "occi/storage/100", verify=False,
data=dumps({}), headers=headers)
print("storage_creation_wrong")
print("---------------")
print("status_code: " + str(req.status_code))
print
print(dumps(loads(req.text), sort_keys=True,
indent=4, separators=(",", ": ")))
print
# query interface
......@@ -67,8 +129,8 @@ with requests.Session() as session:
print("---------------")
print("status_code: " + str(req.status_code))
print
print(json.dumps(json.loads(req.text), sort_keys=True,
indent=4, separators=(",", ": ")))
print(dumps(loads(req.text), sort_keys=True,
indent=4, separators=(",", ": ")))
print
# osszes vm collectionkent
......@@ -78,24 +140,24 @@ with requests.Session() as session:
print("------------------")
print("status_code: " + str(req.status_code))
print
print(json.dumps(json.loads(req.text), sort_keys=True,
indent=4, separators=(",", ": ")))
print(dumps(loads(req.text), sort_keys=True,
indent=4, separators=(",", ": ")))
print
# az elso vm a listabol
vmid = json.loads(req.text)["resources"][0]["id"]
vmid = loads(req.text)["resources"][0]["id"]
req = session.get(server + "occi/compute/" + vmid + "/",
headers=headers, verify=False)
print("compute-" + str(vmid))
print("------------")
print("status_code: " + str(req.status_code))
print
print(json.dumps(json.loads(req.text), sort_keys=True,
indent=4, separators=(",", ": ")))
print(dumps(loads(req.text), sort_keys=True,
indent=4, separators=(",", ": ")))
print
# ha nem active, akkor azza tesszuk
state = json.loads(req.text)["attributes"]["occi.compute.state"]
state = loads(req.text)["attributes"]["occi.compute.state"]
action = "http://schemas.ogf.org/occi/infrastructure/compute/action#"
if state != "active":
try:
......@@ -104,52 +166,52 @@ with requests.Session() as session:
pass
req = session.post(server + "occi/compute/" + vmid + "/",
headers=headers, verify=False,
data=json.dumps({"action": action + "start"}))
data=dumps({"action": action + "start"}))
print("compute-" + str(vmid) + "-start")
print("---------------")
print("status_code: " + str(req.status_code))
print
print(json.dumps(json.loads(req.text), sort_keys=True,
indent=4, separators=(",", ": ")))
print(dumps(loads(req.text), sort_keys=True,
indent=4, separators=(",", ": ")))
print
# restart
try:
headers["X-CSRFToken"] = req.cookies['csrftoken']
except:
pass
actionatrs = {"method": "warm"}
# # restart
# try:
# headers["X-CSRFToken"] = req.cookies['csrftoken']
# except:
# pass
actionatrs = {"method": "cold"}
actioninv = {"action": action + "restart", "attributes": actionatrs}
req = session.post(server + "occi/compute/" + vmid + "/",
headers=headers, verify=False,
data=json.dumps(actioninv))
print("compute-" + str(vmid) + "-restart")
print("-----------------")
print("status_code: " + str(req.status_code))
print
print(json.dumps(json.loads(req.text), sort_keys=True,
indent=4, separators=(",", ": ")))
print
# req = session.post(server + "occi/compute/" + vmid + "/",
# headers=headers, verify=False,
# data=dumps(actioninv))
# print("compute-" + str(vmid) + "-restart")
# print("-----------------")
# print("status_code: " + str(req.status_code))
# print
# print(dumps(loads(req.text), sort_keys=True,
# indent=4, separators=(",", ": ")))
# print
# suspend
# stop
try:
headers["X-CSRFToken"] = req.cookies['csrftoken']
except:
pass
actioninv["action"] = action + "stop"
actioninv["attributes"]["method"] = "graceful"
actioninv["attributes"]["method"] = "poweroff"
req = session.post(server + "occi/compute/" + vmid + "/",
headers=headers, verify=False,
data=json.dumps(actioninv))
data=dumps(actioninv))
print("compute-" + str(vmid) + "-stop")
print("-----------------")
print("status_code: " + str(req.status_code))
print
print(json.dumps(json.loads(req.text), sort_keys=True,
indent=4, separators=(",", ": ")))
print(dumps(loads(req.text), sort_keys=True,
indent=4, separators=(",", ": ")))
print
# nem letezo action
# renew action
try:
headers["X-CSRFToken"] = req.cookies["csrftoken"]
except:
......@@ -157,103 +219,172 @@ with requests.Session() as session:
actioninv["action"] = action + "renew"
req = session.post(server + "occi/compute/" + vmid + "/",
headers=headers, verify=False,
data=json.dumps(actioninv))
data=dumps(actioninv))
print("compute-" + str(vmid) + "-renew")
print("-------------------")
print("status_code: " + str(req.status_code))
print
print(json.dumps(json.loads(req.text), sort_keys=True,
indent=4, separators=(",", ": ")))
print(dumps(loads(req.text), sort_keys=True,
indent=4, separators=(",", ": ")))
print
# vm krealas
# networkinterface add interface
try:
headers["X-CSRFToken"] = req.cookies["csrftoken"]
except:
pass
# a template mixinje benne kell legyen az adatokban
# az osszes template a query interfacen megjelenik mint mixin
# azok a mixinek templatek amik az os_tpl mixintol fuggnek
putdata = {"mixins": [
"http://circlecloud.org/occi/templates/os#os_template_1"],
"other_occi_compute_data": "may be provided"}
req = session.put(server + "occi/compute/1/",
req = session.put(server + "occi/networkinterface/compute" + vmid + "-network3/",
headers=headers, verify=False,
data=json.dumps(putdata))
print("create_compute")
print("--------------")
data=dumps({}))
print("nif-creation")
print("-------------------")
print("status_code: " + str(req.status_code))
print
print(json.dumps(json.loads(req.text), sort_keys=True,
indent=4, separators=(",", ": ")))
print(dumps(loads(req.text), sort_keys=True,
indent=4, separators=(",", ": ")))
print
# vm torles
# networkinterface addport
actionatrs = {"protocol": "tcp", "port": 1111}
actioninv = {"action": "addport", "attributes": actionatrs}
try:
headers["X-CSRFToken"] = req.cookies["csrftoken"]
except:
pass
vmid = json.loads(req.text)["id"]
req = session.delete(server + "occi/compute/" + vmid + "/",
headers=headers, verify=False,
data=json.dumps(putdata))
print("delete_compute")
print("--------------")
req = session.post(server + "occi/networkinterface/compute" + vmid + "-network3/",
headers=headers, verify=False,
data=dumps(actioninv))
print("networkinterface-addport")
print("-------------------")
print("status_code: " + str(req.status_code))
print
print(json.dumps(json.loads(req.text), sort_keys=True,
indent=4, separators=(",", ": ")))
print(dumps(loads(req.text), sort_keys=True,
indent=4, separators=(",", ": ")))
print
# networkinterface removeport
actionatrs = {"protocol": "tcp", "port": 1111}
actioninv = {"action": "removeport", "attributes": actionatrs}
try:
headers["X-CSRFToken"] = req.cookies["csrftoken"]
except:
pass
req = session.get(server + "occi/network/1/", headers=headers,
verify=False)
print("storage")
print("-------")
print("status_code " + str(req.status_code))
req = session.post(server + "occi/networkinterface/compute" + vmid + "-network3/",
headers=headers, verify=False,
data=dumps(actioninv))
print("networkinterface-addport")
print("-------------------")
print("status_code: " + str(req.status_code))
print
print(json.dumps(json.loads(req.text), sort_keys=True,
indent=4, separators=(",", ": ")))
try:
headers["X-CSRFToken"] = req.cookies["csrftoken"]
except:
pass
req = session.post(server + "occi/network/1/", headers=headers,
verify=False, data=json.dumps({"action": "online"}))
print("storage")
print("-------")
print("status_code " + str(req.status_code))
print(dumps(loads(req.text), sort_keys=True,
indent=4, separators=(",", ": ")))
print
print(json.dumps(json.loads(req.text), sort_keys=True,
indent=4, separators=(",", ": ")))
# networkinterface remove interface
try:
headers["X-CSRFToken"] = req.cookies["csrftoken"]
except:
pass
req = session.post(server + "occi/compute/96/", headers=headers,
verify=False, data=json.dumps(
{
"attributes": {
"occi.compute.memory": 0.250
}
}))
print("computerehelelel")
print("-------")
print("status_code " + str(req.status_code))
print
print(json.dumps(json.loads(req.text), sort_keys=True,
indent=4, separators=(",", ": ")))
# Kijelentkezes
req = session.get(server + "occi/logout/", headers=headers,
verify=False)
print("logout")
print("------")
req = session.delete(server + "occi/networkinterface/compute" + vmid + "-network3/",
headers=headers, verify=False)
print("nif-creation")
print("-------------------")
print("status_code: " + str(req.status_code))
print
print(json.dumps(json.loads(req.text), sort_keys=True,
indent=4, separators=(",", ": ")))
print(dumps(loads(req.text), sort_keys=True,
indent=4, separators=(",", ": ")))
print
#
# # vm krealas
# try:
# headers["X-CSRFToken"] = req.cookies["csrftoken"]
# except:
# pass
# # a template mixinje benne kell legyen az adatokban
# # az osszes template a query interfacen megjelenik mint mixin
# # azok a mixinek templatek amik az os_tpl mixintol fuggnek
# putdata = {"mixins": [
# "http://circlecloud.org/occi/templates/os#os_template_1"],
# "other_occi_compute_data": "may be provided"}
# req = session.put(server + "occi/compute/1/",
# headers=headers, verify=False,
# data=dumps(putdata))
# print("create_compute")
# print("--------------")
# print("status_code: " + str(req.status_code))
# print
# print(dumps(loads(req.text), sort_keys=True,
# indent=4, separators=(",", ": ")))
# print
#
# # vm torles
# try:
# headers["X-CSRFToken"] = req.cookies["csrftoken"]
# except:
# pass
# vmid = loads(req.text)["id"]
# req = session.delete(server + "occi/compute/" + vmid + "/",
# headers=headers, verify=False,
# data=dumps(putdata))
# print("delete_compute")
# print("--------------")
# print("status_code: " + str(req.status_code))
# print
# print(dumps(loads(req.text), sort_keys=True,
# indent=4, separators=(",", ": ")))
# print
#
# try:
# headers["X-CSRFToken"] = req.cookies["csrftoken"]
# except:
# pass
# req = session.get(server + "occi/network/1/", headers=headers,
# verify=False)
# print("storage")
# print("-------")
# print("status_code " + str(req.status_code))
# print
# print(dumps(loads(req.text), sort_keys=True,
# indent=4, separators=(",", ": ")))
#
# try:
# headers["X-CSRFToken"] = req.cookies["csrftoken"]
# except:
# pass
# req = session.post(server + "occi/network/1/", headers=headers,
# verify=False, data=dumps({"action": "online"}))
# print("storage")
# print("-------")
# print("status_code " + str(req.status_code))
# print
# print(dumps(loads(req.text), sort_keys=True,
# indent=4, separators=(",", ": ")))
#
# try:
# headers["X-CSRFToken"] = req.cookies["csrftoken"]
# except:
# pass
# req = session.post(server + "occi/compute/96/", headers=headers,
# verify=False, data=dumps(
# {
# "attributes": {
# "occi.compute.memory": 0.250
# }
# }))
# print("computerehelelel")
# print("-------")
# print("status_code " + str(req.status_code))
# print
# print(dumps(loads(req.text), sort_keys=True,
# indent=4, separators=(",", ": ")))
#
# # Kijelentkezes
# req = session.get(server + "occi/logout/", headers=headers,
# verify=False)
# print("logout")
# print("------")
# print("status_code: " + str(req.status_code))
# print
# print(dumps(loads(req.text), sort_keys=True,
# indent=4, separators=(",", ": ")))
......@@ -19,10 +19,10 @@
""" Implementation of the OCCI - Core model classes """
from occi_utils import set_optional_attributes
from occi.utils import set_optional_attributes
class Attribute:
class Attribute(object):
""" OCCI 1.2 - CORE - Classification - Attribute """
TYPES = ("Object", "List", "Hash")
......@@ -36,16 +36,16 @@ class Attribute:
self.required = required
set_optional_attributes(self, self.optional_attributes, kwargs)
def render_as_json(self):
json = {"mutable": self.mutable, "required": self.required,
"type": self.type}
def as_dict(self):
res = {"mutable": self.mutable, "required": self.required,
"type": self.type}
if hasattr(self, "pattern"):
json["pattern"] = self.pattern
res["pattern"] = self.pattern
if hasattr(self, "default"):
json["default"] = self.default
res["default"] = self.default
if hasattr(self, "description"):
json["description"] = self.description
return json
res["description"] = self.description
return res
class Category(object):
......@@ -71,24 +71,23 @@ class Kind(Category):
set_optional_attributes(self, self.kind_optional_attributes,
kwargs)
def render_as_json(self):
json = {"term": self.term, "scheme": self.scheme}
def as_dict(self):
res = {"term": self.term, "scheme": self.scheme}
if hasattr(self, "title"):
json["title"] = self.title
res["title"] = self.title
if hasattr(self, "parent"):
json["parent"] = self.parent
res["parent"] = self.parent
if hasattr(self, "location"):
json["location"] = self.location
res["location"] = self.location
if hasattr(self, "attributes"):
json["attributes"] = {}
res["attributes"] = {}
for attribute in self.attributes:
json["attributes"][attribute.name] = (attribute
.render_as_json())
res["attributes"][attribute.name] = (attribute.as_dict())
if hasattr(self, "actions"):
json["actions"] = []
res["actions"] = []
for action in self.actions:
json["actions"].append(action.scheme + action.term)
return json
res["actions"].append(action.scheme + action.term)
return res
class Action(Category):
......@@ -97,16 +96,15 @@ class Action(Category):
def __init(self, *args, **kwargs):
super(Action, self).__init__(*args, **kwargs)
def render_as_json(self):
json = {"term": self.term, "scheme": self.scheme}
def as_dict(self):
res = {"term": self.term, "scheme": self.scheme}
if hasattr(self, "title"):
json["title"] = self.title
res["title"] = self.title
if hasattr(self, "attributes"):
json["attributes"] = {}
res["attributes"] = {}
for attribute in self.attributes:
json["attributes"][attribute.name] = (attribute
.render_as_json())
return json
res["attributes"][attribute.name] = (attribute.as_dict())
return res
class Mixin(Category):
......@@ -120,26 +118,25 @@ class Mixin(Category):
set_optional_attributes(self, self.mixin_optional_attributes,
kwargs)
def render_as_json(self):
json = {"term": self.term, "scheme": self.scheme}
def as_dict(self):
res = {"term": self.term, "scheme": self.scheme}
if hasattr(self, "title"):
json["title"] = self.title
res["title"] = self.title
if hasattr(self, "location"):
json["location"] = self.location
res["location"] = self.location
if hasattr(self, "depends"):
json["depends"] = self.depends
res["depends"] = self.depends
if hasattr(self, "applies"):
json["applies"] = self.applies
res["applies"] = self.applies
if hasattr(self, "attributes"):
json["attributes"] = {}
res["attributes"] = {}
for attribute in self.attributes:
json["attributes"][attribute.name] = (attribute
.render_as_json())
res["attributes"][attribute.name] = (attribute.as_dict())
if hasattr(self, "actions"):
json["actions"] = []
res["actions"] = []
for action in self.actions:
json["actions"].append(action.scheme + action.term)
return json
res["actions"].append(action.scheme + action.term)
return res
class Entity(object):
......@@ -161,24 +158,24 @@ class Resource(Entity):
def __init__(self, *args, **kwargs):
super(Resource, self).__init__(*args, **kwargs)
set_optional_attributes(self, self.resource_optional_attributes,
kwargs)
set_optional_attributes(
self, self.resource_optional_attributes, kwargs)
def render_as_json(self):
json = {"kind": self.kind, "id": self.id}
def as_dict(self):
res = {"kind": self.kind, "id": self.id}
if hasattr(self, "title"):
json["title"] = self.title
res["title"] = self.title
if hasattr(self, "summary"):
json["summary"] = self.summary
res["summary"] = self.summary
if hasattr(self, "attributes"):
json["attributes"] = self.attributes
res["attributes"] = self.attributes
if hasattr(self, "actions"):
json["actions"] = self.actions
res["actions"] = self.actions
if hasattr(self, "links"):
json["links"] = self.links
res["links"] = self.links
if hasattr(self, "mixins"):
json["mixins"] = self.mixins
return json
res["mixins"] = self.mixins
return res
class Link(Entity):
......@@ -190,18 +187,17 @@ class Link(Entity):
super(Link, self).__init__(*args, **kwargs)
self.source = source
self.target = target
set_optional_attributes(self, self.link_optional_attributes,
kwargs)
set_optional_attributes(self, self.link_optional_attributes, kwargs)
def render_as_json(self):
json = {"kind": self.kind, "id": self.id, "source": self.source,
"target": self.target}
def as_dict(self):
res = {"kind": self.kind, "id": self.id, "source": self.source,
"target": self.target}
if hasattr(self, "mixins"):
json["mixins"] = self.mixins
res["mixins"] = self.mixins
if hasattr(self, "attributes"):
json["attributes"] = self.attributes
res["attributes"] = self.attributes
if hasattr(self, "actions"):
json["actions"] = self.actions
res["actions"] = self.actions
if hasattr(self, "title"):
json["title"] = self.title
return json
res["title"] = self.title
return res
......@@ -19,12 +19,13 @@
""" Implementation of the OCCI - Infrastructure extension classes """
from occi_core import Resource, Link
from occi_utils import action_list_for_resource, OcciActionInvocationError
from occi_instances import (COMPUTE_ACTIONS, LEASETIME_ACTIONS,
from occi.core import Resource, Link
from occi.utils import action_list_for_resource, OcciActionInvocationError
from occi.instances import (COMPUTE_ACTIONS, LEASETIME_ACTIONS,
STORAGE_ACTIONS, NETWORK_ACTIONS)
from common.models import HumanReadableException
from celery.exceptions import TimeoutError
from firewall.models import Rule
import logging
......@@ -117,11 +118,11 @@ class Compute(Resource):
for disk in disks:
storages.append(Storage(disk))
for storage in storages:
links.append(StorageLink(self, storage).render_as_json())
links.append(StorageLink(self, storage).as_dict())
nics = [NetworkInterface(self, Network(nic.vlan))
for nic in self.vm.interface_set.all()]
for networkinterface in nics:
links.append(networkinterface.render_as_json())
links.append(networkinterface.as_dict())
return links
def invoke_action(self, user, action, attributes):
......@@ -137,6 +138,10 @@ class Compute(Resource):
self.save(user, attributes)
elif action.endswith("renew"):
self.renew(user)
elif action.endswith("createstorage"):
self.create_disk(user, attributes)
elif action.endswith("downloadstorage"):
self.download_disk(user, attributes)
else:
raise OcciActionInvocationError(message="Undefined action.")
self.__init__(self.vm)
......@@ -147,6 +152,28 @@ class Compute(Resource):
except HumanReadableException as e:
raise OcciActionInvocationError(message=e.get_user_text())
def create_disk(self, user, attributes):
if "size" not in attributes:
raise OcciActionInvocationError(
message="Storage size is missing from action attributes!"
)
try:
self.vm.create_disk(user=user, size=attributes["size"],
name=attributes.get("name"))
except HumanReadableException as e:
raise OcciActionInvocationError(message=e.get_user_text())
def download_disk(self, user, attributes):
if "url" not in attributes:
raise OcciActionInvocationError(
message="Storage image url is missing from action attributes!"
)
try:
self.vm.download_disk(user=user, url=attributes["url"],
name=attributes.get("name"))
except HumanReadableException as e:
raise OcciActionInvocationError(message=e.get_user_text())
def start(self, user):
""" Start action on a compute instance """
try:
......@@ -371,9 +398,50 @@ class NetworkInterface(Link):
self.mixins = [
("http://schemas.ogf.org/occi/infrastructure/networkinterface#" +
"ipnetworkinterface"),
("http://circlecloud.org/occi/infrastructure/networkinterface#" +
"ports"),
]
self.attributes = self.set_attributes()
def invoke_action(self, user, action, attributes):
if action.endswith("addport"):
self.addport(user, attributes)
elif action.endswith("removeport"):
self.removeport(user, attributes)
else:
raise OcciActionInvocationError(message="Undefined action.")
self.__init__(Compute(self.compute.vm), Network(self.network.vlan))
def addport(self, user, attributes):
if "port" not in attributes or "protocol" not in attributes:
raise OcciActionInvocationError(
message="Please supply the protocol and the port!")
try:
self.compute.vm.add_port(user=user, host=self.interface.host,
proto=attributes["protocol"],
port=int(attributes["port"]))
except HumanReadableException as e:
raise OcciActionInvocationError(message=e.get_user_text())
except AttributeError:
raise OcciActionInvocationError(
message="Unmanaged interfaces cant add ports."
)
def removeport(self, user, attributes):
if "port" not in attributes or "protocol" not in attributes:
raise OcciActionInvocationError(
message="Please supply the protocol and the port!")
try:
rule = Rule.objects.filter(host=self.interface.host).filter(
dport=attributes["port"]).get(
proto=attributes["protocol"])
except Rule.DoesNotExist:
raise OcciActionInvocationError(message="Port does not exist!")
try:
self.compute.vm.remove_port(user=user, rule=rule)
except HumanReadableException as e:
raise OcciActionInvocationError(message=e.get_user_text())
def set_attributes(self):
attributes = {}
attributes["occi.networkinterface.interface"] = (
......@@ -382,10 +450,17 @@ class NetworkInterface(Link):
attributes["occi.networkinterface.state"] = "active"
attributes["occi.networkinterface.state.message"] = (
"The networkinterface is active.")
attributes["occi.networkinterface.address"] = (
unicode(self.interface.host.ipv4))
if self.interface.host:
attributes["occi.networkinterface.address"] = (
unicode(self.interface.host.ipv4))
attributes["occi.networkinterface.gateway"] = (
unicode(self.interface.vlan.network4.ip))
attributes["occi.networkinterface.allocation"] = (
self.network.attributes["occi.network.allocation"])
attributes["org.circlecloud.occi.networkinterface.ports"] = (
self.get_open_ports())
return attributes
def get_open_ports(self):
return [{"port": rule.dport, "protocol": rule.proto}
for rule in Rule.objects.filter(host=self.interface.host)]
......@@ -19,7 +19,7 @@
""" Required instances of the OCCI classes """
from vm.models.instance import InstanceTemplate
from occi_core import Kind, Mixin, Attribute, Action
from occi.core import Kind, Mixin, Attribute, Action
ENTITY_KIND = Kind("http://schemas.ogf.org/occi/core#", "entity",
......@@ -237,6 +237,42 @@ CREDENTIALS_MIXIN = Mixin("http://circlecloud.org/occi/infrastructure/" +
applies="http://schemas.ogf.org/occi/" +
"infrastructure#compute")
NETWORKINTERFACE_PORTS_ATTRIBUTES = [
Attribute("org.circlecloud.occi.networkinterface.ports", "List", False,
False, description="A list of open ports on the interface."),
]
NETWORKINTERFACE_PORTS_ACTIONS = [
Action(
"http://schemas.ogf.org/occi/infrastructure/networkinterface/action#",
"addport",
title="Open a port on a network interface.",
attributes=[
Attribute("protocol", "Enum {tcp, udp, icmp}", True, False),
Attribute("port", "Integer", False, True),
],
),
Action(
"http://schemas.ogf.org/occi/infrastructure/networkinterface/action#",
"removeport",
title="Closes a port on a network interface.",
attributes=[
Attribute("protocol", "Enum {tcp, udp, icmp}", True, False),
Attribute("port", "Integer", False, True),
],
),
]
NETWORKINTERFACE_PORTS_MIXIN = Mixin(
"http://circlecloud.org/occi/infrastructure/networkinterface#",
"ports",
title="Network interface ports mixin",
attributes=NETWORKINTERFACE_PORTS_ATTRIBUTES,
actions=NETWORKINTERFACE_PORTS_ACTIONS,
applies="http://schemas.ogf.org/occi/infrastructure#networkinterface",
)
LEASETIME_ATTRIBUTES = [
Attribute("org.circlecloud.occi.leasetime.suspend", "String", False,
False, description="The time remaining until the compute " +
......@@ -264,11 +300,13 @@ OS_TPL_MIXIN = Mixin("http://schemas.ogf.org/occi/infrastructure#",
"os_tpl",
title="OS Template")
ACTION_ARRAYS = [
COMPUTE_ACTIONS,
NETWORK_ACTIONS,
STORAGE_ACTIONS,
LEASETIME_ACTIONS,
NETWORKINTERFACE_PORTS_ACTIONS,
]
......@@ -290,10 +328,38 @@ def os_tpl_mixins(user):
templates = InstanceTemplate.get_objects_with_level("user", user)
result = []
for template in templates:
result.append(Mixin("http://circlecloud.org/occi/templates/os#",
"os_template_" + str(template.pk),
title=template.name,
depends=(OS_TPL_MIXIN.scheme + OS_TPL_MIXIN.term)))
template_attrs = [
Attribute("occi.compute.architecture", "Enum {x86, x64}",
True, False,
default={
"x86_64": "x64",
"x86-64 (64 bit)": "x64",
"i686": "x86",
"x86 (32 bit)": "x86"
}[template.arch],
description="CPU Architecture of the instance."),
Attribute("occi.compute.cores", "Integer", True, False,
default=template.num_cores,
description="Number of virtual CPU cores assigned to " +
"the instance."),
Attribute("occi.compute.share", "Integer", True, False,
default=template.priority,
description="Relative number of CPU shares for the " +
"instance."),
Attribute("occi.compute.memory", "Float, 10^9 (GiB)", True, False,
default=template.ram_size,
description="Maximum RAM in gigabytes allocated to " +
"the instance."),
]
result.append(
Mixin(
"http://circlecloud.org/occi/templates/os#",
"os_template_" + str(template.pk),
title=template.name,
depends=(OS_TPL_MIXIN.scheme + OS_TPL_MIXIN.term),
attributes=template_attrs,
)
)
return result
......@@ -304,6 +370,7 @@ def ALL_MIXINS(user):
CREDENTIALS_MIXIN,
OS_TPL_MIXIN,
LEASETIME_MIXIN,
NETWORKINTERFACE_PORTS_MIXIN,
]
template_mixins = os_tpl_mixins(user)
for template in template_mixins:
......
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import ensure_csrf_cookie
from occi.utils import OcciRequestNotValid
class EnsureCsrfTokenMixin(object):
@method_decorator(ensure_csrf_cookie)
def dispatch(self, *args, **kwargs):
return super(EnsureCsrfTokenMixin, self).dispatch(*args, **kwargs)
class OcciViewMixin(EnsureCsrfTokenMixin):
def dispatch(self, request, *args, **kwargs):
if not request.user.is_authenticated():
return OcciRequestNotValid(message="Authentication required.",
status=403).response
return super(OcciViewMixin, self).dispatch(request, *args, **kwargs)
......@@ -17,13 +17,18 @@
from django.conf.urls import url
from views import (OcciLoginView, OcciLogoutView, OcciQueryInterfaceView,
OcciComputeView, OcciComputeCollectionView,
OcciStorageView, OcciStorageCollectionView,
OcciNetworkView, OcciNetworkCollectionView)
from occi.views import (OcciLoginView, OcciLogoutView, OcciQueryInterfaceView,
OcciComputeView, OcciComputeCollectionView,
OcciStorageView, OcciStorageCollectionView,
OcciNetworkView, OcciNetworkCollectionView,
OcciStoragelinkView, OcciStoragelinkCollectionView,
OcciNetworkInterfaceView,
OcciNetworkInterfaceCollectionView,)
from common.views import GenerateTokenView
urlpatterns = [
url(r'^login/token/$', GenerateTokenView.as_view()),
url(r'^login/$', OcciLoginView.as_view()),
url(r'^logout/$', OcciLogoutView.as_view()),
url(r'^-/$', OcciQueryInterfaceView.as_view()),
......@@ -33,4 +38,11 @@ urlpatterns = [
url(r'^storage/(?P<id>\d+)/$', OcciStorageView.as_view()),
url(r'^network/$', OcciNetworkCollectionView.as_view()),
url(r'^network/(?P<id>\d+)/$', OcciNetworkView.as_view()),
url(r'^storagelink/$', OcciStoragelinkCollectionView.as_view()),
url(r'^storagelink/compute(?P<computeid>\d+)-storage(?P<storageid>\d+)/$',
OcciStoragelinkView.as_view()),
url(r'^networkinterface/$', OcciNetworkInterfaceCollectionView.as_view()),
url(r'^networkinterface/compute(?P<computeid>\d+)-network(?P<networkid>' +
r'\d+)/$',
OcciNetworkInterfaceView.as_view()),
]
......@@ -18,7 +18,7 @@
"""" Utilities for the OCCI implementation of CIRCLE """
from django.http import HttpResponse
from django.http import JsonResponse
import json
......@@ -89,44 +89,33 @@ def occi_response(data, *args, **kwargs):
by default. """
status = kwargs.get("status", 200)
# TODO: support for renderings other than json (e.g., text/plain)
data = json.dumps(data)
response = HttpResponse(data, charset="utf-8", status=status,
content_type="application/json; charset=utf-8")
response = JsonResponse(data, status=status)
# TODO: use Server header instead of OCCI-Server
response["OCCI-Server"] = "OCCI/1.2"
response["Accept"] = "application/json"
return response
def validate_request(request, authentication_required=True,
has_data=False, **kwargs):
""" This function checks if the request's content type is
application/json and if the data is a valid json object. If the
authentication_required parameter is 'True', it will also check if
the user is authenticated. """
# checking if the user is authenticated
if authentication_required:
if not request.user.is_authenticated():
raise OcciRequestNotValid("Authentication required.", status=403)
if has_data:
# checking content type
if request.META.get("CONTENT_TYPE") != "application/json":
raise OcciRequestNotValid("Only application/json content type" +
" is allowed.")
# checking if the data is a valid json
try:
data = json.loads(request.body.decode("utf-8"))
except KeyError:
raise OcciRequestNotValid("The json provided in the request is " +
"not valid.")
# checking if provided keys are in the json
if "data_keys" in kwargs:
for key in kwargs["data_keys"]:
if key not in data:
raise OcciRequestNotValid(key + " key is required.")
# if validation was successful, the function returns the parsed
# json data
return data
def validate_request_data(request, data_keys):
""" This function checks if all the required data keys are set and if the
input is a valid json object. """
# checking content type
if request.META.get("CONTENT_TYPE") != "application/json":
raise OcciRequestNotValid("Only application/json content type" +
" is allowed.")
# checking if the data is a valid json
try:
data = json.loads(request.body.decode("utf-8"))
except KeyError:
raise OcciRequestNotValid("The json provided in the request is " +
"not valid.")
# checking if provided keys are in the json
for key in data_keys:
if key not in data:
raise OcciRequestNotValid(key + " key is required.")
# if validation was successful, the function returns the parsed
# json data
return data
def set_optional_attributes(self, optional_attributes, kwargs):
......
......@@ -25,33 +25,33 @@ from django.views.generic import View
from django.contrib.auth import logout
from django.http import Http404
from django.shortcuts import get_object_or_404
from django.views.decorators.csrf import ensure_csrf_cookie
from django.utils.decorators import method_decorator
from vm.models.instance import Instance, InstanceTemplate
from storage.models import Disk
from firewall.models import Vlan
from forms import OcciAuthForm
from occi_infrastructure import Compute, Storage, Network
from occi_utils import (OcciResourceInstanceNotExist,
from occi.forms import OcciAuthForm
from occi.infrastructure import (Compute, Storage, Network, StorageLink,
NetworkInterface,)
from occi.utils import (OcciResourceInstanceNotExist,
OcciActionInvocationError,
OcciRequestNotValid,
OcciResourceCreationError,
OcciResourceDeletionError,
occi_response,
validate_request)
from occi_instances import ALL_KINDS, ALL_MIXINS, ALL_ACTIONS
validate_request_data)
from occi.instances import ALL_KINDS, ALL_MIXINS, ALL_ACTIONS
from common.models import HumanReadableException
from occi.mixins import OcciViewMixin, EnsureCsrfTokenMixin
import logging
log = logging.getLogger(__name__)
class OcciLoginView(View):
class OcciLoginView(EnsureCsrfTokenMixin, View):
""" Authentication for the usage of the OCCI api.
This view responds with 200 and the access token in a Cookie if the
authentication succeeded, and with 400 if the provided username and
password is not valid. """
@method_decorator(ensure_csrf_cookie)
def get(self, request, *args, **kwargs):
""" Returns a response with a cookie to be used for requests other
than get. """
......@@ -62,8 +62,6 @@ class OcciLoginView(View):
""" Returns a response with a cookie to be used for the OCCI api
requests. """
data = json.loads(request.body.decode("utf-8"))
log.error(data)
print(data)
form = OcciAuthForm(data=data, request=request)
if form.is_valid():
result = {"result": "OK"}
......@@ -75,7 +73,7 @@ class OcciLoginView(View):
return occi_response(result, status=400)
class OcciLogoutView(View):
class OcciLogoutView(EnsureCsrfTokenMixin, View):
""" Logout """
def get(self, request, *args, **kwargs):
......@@ -84,21 +82,17 @@ class OcciLogoutView(View):
return occi_response(result)
class OcciQueryInterfaceView(View):
class OcciQueryInterfaceView(OcciViewMixin, View):
""" The view of the OCCI query interface """
@method_decorator(ensure_csrf_cookie)
def get(self, request, *args, **kwargs):
try:
validate_request(request)
except OcciRequestNotValid as e:
return e.response
result = {"kinds": [], "mixins": [], "actions": []}
for kind in ALL_KINDS():
result["kinds"].append(kind.render_as_json())
for mixin in ALL_MIXINS(request.user):
result["mixins"].append(mixin.render_as_json())
for action in ALL_ACTIONS():
result["actions"].append(action.render_as_json())
result["kinds"].append(kind.as_dict())
result["mixins"] = [mixin.as_dict() for mixin in
ALL_MIXINS(request.user)]
result["actions"] = [action.as_dict()
for action in ALL_ACTIONS()]
return occi_response(result)
def post(self, request, *args, **kwargs):
......@@ -114,32 +108,20 @@ class OcciQueryInterfaceView(View):
"query interface."}, status=400)
class OcciComputeCollectionView(View):
@method_decorator(ensure_csrf_cookie)
class OcciComputeCollectionView(OcciViewMixin, View):
def get(self, request, *args, **kwargs):
try:
validate_request(request)
except OcciRequestNotValid as e:
return e.response
vms = (Instance.get_objects_with_level("owner", request.user)
.filter(destroyed_at=None))
json = {"resources": []}
for vm in vms:
json["resources"].append(Compute(vm).render_as_json())
return occi_response(json)
resources = [Compute(vm).as_dict()
for vm in Instance.get_objects_with_level(
"owner", request.user).filter(destroyed_at=None)]
return occi_response({"resources": resources})
def put(self, request, *args, **kwargs):
# TODO: vm creation
return occi_response({"message": "TODO"})
try:
Instance.create_from_template(
InstanceTemplate.objects.get(pk=1), request.user)
except Exception:
return occi_response({"test": "tset"})
return occi_response({})
class OcciComputeView(View):
class OcciComputeView(OcciViewMixin, View):
""" View of a compute instance """
def get_vm_object(self, user, vmid):
......@@ -150,16 +132,12 @@ class OcciComputeView(View):
raise OcciResourceInstanceNotExist()
return Compute(vm)
@method_decorator(ensure_csrf_cookie)
def get(self, request, *args, **kwargs):
if not request.user.is_authenticated():
return occi_response({"error": "Authentication required."},
status=403)
try:
compute = self.get_vm_object(request.user, kwargs["id"])
except OcciResourceInstanceNotExist as e:
return e.response
return occi_response(compute.render_as_json(), charset="utf-8")
return occi_response(compute.as_dict(), charset="utf-8")
def post(self, request, *args, **kwargs):
requestData = json.loads(request.body.decode("utf-8"))
......@@ -174,7 +152,7 @@ class OcciComputeView(View):
requestData.get("attributes", None))
except OcciActionInvocationError as e:
return e.response
return occi_response(compute.render_as_json(), status=200)
return occi_response(compute.as_dict(), status=200)
elif "attributes" in requestData:
attrs = requestData["attributes"]
try:
......@@ -197,7 +175,7 @@ class OcciComputeView(View):
)
except HumanReadableException as e:
log.warning(e.get_user_text())
return occi_response(Compute(vm).render_as_json(), status=200)
return occi_response(Compute(vm).as_dict(), status=200)
return occi_response({"error": "Bad request"}, status=400)
def put(self, request, *args, **kwargs):
......@@ -208,8 +186,8 @@ class OcciComputeView(View):
# there has to be a mixins array in the provided rendering
data_keys = ["mixins"]
try:
requestData = validate_request(request, True, True,
data_keys=data_keys)
requestData = validate_request_data(request,
data_keys=data_keys)
except OcciRequestNotValid as e:
return e.response
ostpl = "http://circlecloud.org/occi/templates/os#os_template_"
......@@ -229,7 +207,7 @@ class OcciComputeView(View):
except:
return OcciResourceCreationError().response
compute = Compute(vm)
return occi_response(compute.render_as_json())
return occi_response(compute.as_dict())
# TODO: update compute instance
return occi_response({"error": "Update of compute instances is " +
"not implemented."}, status=501)
......@@ -246,28 +224,23 @@ class OcciComputeView(View):
return occi_response({"result": "Compute instance deleted."})
class OcciStorageCollectionView(View):
class OcciStorageCollectionView(OcciViewMixin, View):
@method_decorator(ensure_csrf_cookie)
def get(self, request, *args, **kwargs):
try:
validate_request(request)
except OcciRequestNotValid as e:
return e.response
vms = (Instance.get_objects_with_level("owner", request.user)
.filter(destroyed_at=None))
json = {"resources": []}
for vm in vms:
disks = vm.disks.all()
for disk in disks:
json["resources"].append(Storage(disk).render_as_json())
json["resources"].append(Storage(disk).as_dict())
return occi_response(json)
def put(self, request, *args, **kwargs):
return occi_response({"message": "Not supported."}, status=501)
class OcciStorageView(View):
class OcciStorageView(OcciViewMixin, View):
""" View of a storage instance """
def get_disk_object(self, user, diskid):
......@@ -283,17 +256,12 @@ class OcciStorageView(View):
return Storage(disk)
raise OcciResourceInstanceNotExist()
@method_decorator(ensure_csrf_cookie)
def get(self, request, *args, **kwargs):
try:
validate_request(request)
except OcciRequestNotValid as e:
return e.response
try:
disk = self.get_disk_object(request.user, kwargs["id"])
except OcciResourceInstanceNotExist as e:
return e.response
return occi_response(disk.render_as_json(), charset="utf-8")
return occi_response(disk.as_dict(), charset="utf-8")
def post(self, request, *args, **kwargs):
requestData = json.loads(request.body.decode("utf-8"))
......@@ -315,24 +283,26 @@ class OcciStorageView(View):
requestData.get("attributes", None))
except OcciActionInvocationError as e:
return e.response
return occi_response(storage.render_as_json(), status=200)
return occi_response(storage.as_dict(), status=200)
def put(self, request, *args, **kwargs):
return OcciResourceCreationError(
message="Storage creation is not supported at this uri. " +
"Please use the compute instances' actions!"
).response
class OcciNetworkCollectionView(OcciViewMixin, View):
class OcciNetworkCollectionView(View):
@method_decorator(ensure_csrf_cookie)
def get(self, request, *args, **kwargs):
try:
validate_request(request)
except OcciRequestNotValid as e:
return e.response
vlans = (Vlan.get_objects_with_level("owner", request.user))
json = {"resources": []}
for vlan in vlans:
json["resources"].append(Network(vlan).render_as_json())
json["resources"].append(Network(vlan).as_dict())
return occi_response(json)
class OcciNetworkView(View):
class OcciNetworkView(OcciViewMixin, View):
""" View of a compute instance """
def get_vlan_object(self, user, vlanid):
......@@ -343,17 +313,12 @@ class OcciNetworkView(View):
raise OcciResourceInstanceNotExist()
return Network(vlan)
@method_decorator(ensure_csrf_cookie)
def get(self, request, *args, **kwargs):
try:
validate_request(request)
except OcciRequestNotValid as e:
return e.response
try:
network = self.get_vlan_object(request.user, kwargs["id"])
except OcciResourceInstanceNotExist as e:
return e.response
return occi_response(network.render_as_json(), charset="utf-8")
return occi_response(network.as_dict(), charset="utf-8")
def post(self, request, *args, **kwargs):
requestData = json.loads(request.body.decode("utf-8"))
......@@ -375,4 +340,135 @@ class OcciNetworkView(View):
requestData.get("attributes", None))
except OcciActionInvocationError as e:
return e.response
return occi_response(network.render_as_json(), status=200)
return occi_response(network.as_dict(), status=200)
class OcciStoragelinkCollectionView(OcciViewMixin, View):
""" View of all storage link instances of the user """
def get(self, request, *args, **kwargs):
vms = (Instance.get_objects_with_level("owner", request.user)
.filter(destroyed_at=None))
links = [StorageLink(Compute(vm), Storage(disk)).as_dict()
for vm in vms for disk in vm.disks.all()]
return occi_response({"links": links})
class OcciStoragelinkView(OcciViewMixin, View):
""" VIew of a storage link instance """
def get(self, request, *args, **kwargs):
try:
vm = get_object_or_404(Instance.get_objects_with_level(
"owner", request.user).filter(destroyed_at=None),
pk=kwargs["computeid"])
except Http404:
return OcciResourceInstanceNotExist().response
try:
disk = vm.disks.get(pk=kwargs["storageid"])
except Disk.DoesNotExist:
return OcciResourceInstanceNotExist().response
return occi_response(
StorageLink(Compute(vm), Storage(disk)).as_dict())
class OcciNetworkInterfaceCollectionView(OcciViewMixin, View):
""" View of network interface instances of a user """
def get(self, request, *args, **kwargs):
vms = (Instance.get_objects_with_level("owner", request.user)
.filter(destroyed_at=None))
links = [NetworkInterface(Compute(vm),
Network(nwi.vlan)).as_dict()
for vm in vms for nwi in vm.interface_set.all()]
return occi_response({"links": links})
class OcciNetworkInterfaceView(OcciViewMixin, View):
""" View of a network interface instance """
def get_compute_object(self, user, vmid):
try:
vm = get_object_or_404(Instance.get_objects_with_level(
"owner", user).filter(destroyed_at=None), pk=vmid)
except Http404:
raise OcciResourceInstanceNotExist()
return Compute(vm)
def get_network_object(self, user, vlanid):
try:
vlan = get_object_or_404(Vlan.get_objects_with_level(
"user", user), pk=vlanid)
except Http404:
raise OcciResourceInstanceNotExist()
return Network(vlan)
def get_networkinterface_object(self, user, vmid, vlanid):
compute = self.get_compute_object(user, vmid)
try:
interface = compute.vm.interface_set.get(vlan__pk=vlanid)
except:
raise OcciResourceInstanceNotExist()
return NetworkInterface(compute, Network(interface.vlan))
def get(self, request, *args, **kwargs):
try:
nic = self.get_networkinterface_object(
request.user, kwargs["computeid"], kwargs["networkid"])
except OcciResourceInstanceNotExist as e:
return e.response
return occi_response(nic.as_dict())
def post(self, request, *args, **kwargs):
requestData = json.loads(request.body.decode("utf-8"))
if "action" in requestData:
try:
nif = self.get_networkinterface_object(
request.user, kwargs["computeid"], kwargs["networkid"])
except OcciResourceInstanceNotExist as e:
return e.response
try:
nif.invoke_action(request.user,
requestData.get("action", None),
requestData.get("attributes", None))
except OcciActionInvocationError as e:
return e.response
return occi_response(nif.as_dict(), status=200)
return OcciActionInvocationError().response
def put(self, request, *args, **kwargs):
compute = self.get_compute_object(request.user, kwargs["computeid"])
network = self.get_network_object(request.user, kwargs["networkid"])
try:
compute.vm.add_interface(user=request.user, vlan=network.vlan)
except HumanReadableException as e:
return OcciResourceCreationError(
message=e.get_user_text()).response
except Exception as e:
return OcciResourceCreationError(message=unicode(e)).response
nif = NetworkInterface(compute, network)
return occi_response(nif.as_dict())
def delete(self, request, *args, **kwargs):
compute = self.get_compute_object(request.user, kwargs["computeid"])
network = self.get_network_object(request.user, kwargs["networkid"])
try:
interface = compute.vm.interface_set.get(vlan=network.vlan)
except:
return OcciResourceInstanceNotExist().response
try:
from firewall.models import Host
from vm.models.network import Interface
hc = Host.objects.filter(mac=interface.host.mac).count()
ic = Interface.objects.filter(host__mac=interface.host.mac).count()
compute.vm.remove_interface(user=request.user, interface=interface)
except HumanReadableException as e:
return OcciResourceDeletionError(
message=e.get_user_text()).response
except Exception:
from firewall.models import Host
from vm.models.network import Interface
hc = Host.objects.filter(mac=interface.host.mac).count()
ic = Interface.objects.filter(host__mac=interface.host.mac).count()
return occi_response({"host": hc, "interface": ic})
return occi_response({"status": "ok"})
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment