Commit ad2ae089 authored by Pavel Spirek's avatar Pavel Spirek

DELETE method implemented

parent e4be8dfa
......@@ -9,7 +9,7 @@ from colorlog import error, warning as warn, info, debug
from typing import List, Any, Dict, TypeVar, Tuple, Set
import copy
import yangson.instance
from yangson.instance import Instance, NonexistentInstance, InstanceError, ArrayValue, ObjectValue, MemberName, EntryKeys
from yangson.instance import Instance, NonexistentInstance, InstanceError, ArrayValue, ObjectValue, MemberName, EntryKeys, EntryIndex
from yangson import DataModel
from yangson.datamodel import InstanceIdentifier
from .helpers import DataHelpers
......@@ -172,6 +172,29 @@ class BaseDatastore:
new_n = n.update(inst_val)
self._data = new_n.top()
def delete_node_rpc(self, rpc: Rpc, insert=None, point=None):
ii = self.parse_ii(rpc.path, rpc.path_format)
n = self._data.goto(ii)
n_parent = n.up()
last_isel = ii[-1]
# if self.nacm:
# nrpc = NacmRpc(self.nacm, self, rpc.username)
# if nrpc.check_data_node_path(ii, Permission.NACM_ACCESS_READ) == Action.DENY:
# raise NacmForbiddenError()
# else:
# # Prun subtree data
# n = nrpc.check_data_read_path(ii)
if isinstance(last_isel, EntryIndex):
new_n = n_parent.remove_entry(last_isel.index)
elif isinstance(last_isel, EntryKeys):
new_n = n_parent.remove_entry(n.crumb.pointer_fragment())
elif isinstance(last_isel, MemberName):
new_n = n_parent.remove_member(last_isel.name)
self._data = new_n.top()
# Locks datastore data
def lock_data(self, username: str = None, blocking: bool=True):
ret = self._data_lock.acquire(blocking=blocking, timeout=1)
......
......@@ -6,7 +6,7 @@ from colorlog import error, warning as warn, info, debug
from urllib.parse import parse_qs
from yangson.schema import NonexistentSchemaNode
from yangson.instance import NonexistentInstance
from yangson.instance import NonexistentInstance, InstanceTypeError
from .config import CONFIG_HTTP, NACM_ADMINS, API_ROOT_data, NACM_API_ROOT_data
from .helpers import CertHelpers
......@@ -61,6 +61,10 @@ def get(prot: "H2Protocol", headers: OrderedDict, stream_id: int, ds, pth):
warn("NonexistentInstance: " + pth)
response = "NonexistentInstance"
http_status = "404"
except InstanceTypeError:
warn("InstanceTypeError: " + pth)
response = "InstanceTypeError"
http_status = "404"
finally:
ds.unlock_data()
......@@ -250,3 +254,68 @@ def create_put_post_nacm_api(ds: BaseDatastore):
prot.conn.send_data(stream_id, response, end_stream=True)
return put_post_nacm_api_closure
def create_nacm_api_delete(ds: BaseDatastore):
def put_post_nacm_api_closure(prot: "H2Protocol", headers: OrderedDict, stream_id: int):
url_split = headers[":path"].split("?")
path = url_split[0]
if len(url_split) > 1:
query_string = parse_qs(url_split[1])
else:
query_string = {}
info(("nacm_api_delete: " + path))
info("qs = {}".format(query_string))
username = CertHelpers.get_field(prot.client_cert, "emailAddress")
pth = path[len(NACM_API_ROOT_data):]
rpc1 = Rpc()
rpc1.username = username
rpc1.path = pth
try:
ds.nacm.nacm_ds.lock_data(username)
ds.nacm.nacm_ds.delete_node_rpc(rpc1)
response = "No Content"
http_status = "204"
except DataLockError as e:
warn(e.msg)
response = "Internal Server Error"
http_status = "500"
except NacmForbiddenError as e:
warn(e.msg)
response = "Forbidden"
http_status = "403"
except NonexistentSchemaNode:
warn("NonexistentSchemaNode: " + pth)
response = "NonexistentSchemaNode"
http_status = "404"
except NonexistentInstance:
warn("NonexistentInstance: " + pth)
response = "NonexistentInstance"
http_status = "404"
except InstanceAlreadyPresent:
warn("InstanceAlreadyPresent: " + pth)
response = "Conflict"
http_status = "409"
finally:
ds.nacm.nacm_ds.unlock_data()
ds.nacm.update(ds.nacm.nacm_ds.get_data_root().member("ietf-netconf-acm:nacm"))
response += "\n"
response = response.encode()
response_headers = (
(':status', http_status),
('content-type', 'application/yang.api+json'),
('content-length', len(response)),
('server', CONFIG_HTTP["SERVER_NAME"]),
)
prot.conn.send_headers(stream_id, response_headers)
prot.conn.send_data(stream_id, response, end_stream=True)
return put_post_nacm_api_closure
......@@ -58,9 +58,9 @@ class H2Protocol(asyncio.Protocol):
headers = OrderedDict(event.headers)
http_method = headers[":method"]
if http_method == "GET":
# Handle GET
self.handle_get(headers, event.stream_id)
if http_method in ("GET", "DELETE"):
# Handle immediately, no need to wait for incoming data
self.handle_get_delete(headers, event.stream_id)
elif http_method in ("PUT", "POST"):
# Store headers and wait for data upload
self.reqs_waiting_upload[event.stream_id] = headers
......@@ -71,8 +71,6 @@ class H2Protocol(asyncio.Protocol):
elif isinstance(event, RemoteSettingsChanged):
self.conn.acknowledge_settings(event)
self.transport.write(self.conn.data_to_send())
def http_handle_upload(self, data: bytes, stream_id: int):
try:
headers = self.reqs_waiting_upload.pop(stream_id)
......@@ -83,22 +81,22 @@ class H2Protocol(asyncio.Protocol):
url_split = headers[":path"].split("?")
url_path = url_split[0]
h = gl_handlers.get_handler(headers[":method"], url_path)
h = h2_handlers.get_handler(headers[":method"], url_path)
if h:
h(self, headers, data, stream_id)
def handle_get(self, headers: OrderedDict, stream_id: int):
# Handle GET
def handle_get_delete(self, headers: OrderedDict, stream_id: int):
# Handle GET, DELETE
url_split = headers[":path"].split("?")
url_path = url_split[0]
h = gl_handlers.get_handler("GET", url_path)
h = h2_handlers.get_handler(headers[":method"], url_path)
if h:
h(self, headers, stream_id)
def run():
global gl_handlers
global h2_handlers
# Load configuration
load_config("jetconf/config.yaml")
......@@ -119,14 +117,16 @@ def run():
get_api = handlers.create_get_api(ex_datastore)
get_nacm_api = handlers.create_get_nacm_api(ex_datastore)
put_post_nacm_api = handlers.create_put_post_nacm_api(ex_datastore)
gl_handlers = HandlerList()
gl_handlers.register_handler(lambda m, p: (m == "POST") and (p.startswith(NACM_API_ROOT_data)), put_post_nacm_api)
gl_handlers.register_handler(lambda m, p: (m == "GET") and (p == CONFIG_HTTP["NACM_API_ROOT"]), handlers.api_root_handler)
gl_handlers.register_handler(lambda m, p: (m == "GET") and (p == CONFIG_HTTP["API_ROOT"]), handlers.api_root_handler)
gl_handlers.register_handler(lambda m, p: (m == "GET") and (p.startswith(NACM_API_ROOT_data)), get_nacm_api)
gl_handlers.register_handler(lambda m, p: (m == "GET") and (p.startswith(API_ROOT_data)), get_api)
gl_handlers.register_handler(lambda m, p: m == "GET", handlers.get_file)
nacm_api_delete = handlers.create_nacm_api_delete(ex_datastore)
h2_handlers = HandlerList()
h2_handlers.register_handler(lambda m, p: (m == "POST") and (p.startswith(NACM_API_ROOT_data)), put_post_nacm_api)
h2_handlers.register_handler(lambda m, p: (m == "DELETE") and (p.startswith(NACM_API_ROOT_data)), nacm_api_delete)
h2_handlers.register_handler(lambda m, p: (m == "GET") and (p == CONFIG_HTTP["NACM_API_ROOT"]), handlers.api_root_handler)
h2_handlers.register_handler(lambda m, p: (m == "GET") and (p == CONFIG_HTTP["API_ROOT"]), handlers.api_root_handler)
h2_handlers.register_handler(lambda m, p: (m == "GET") and (p.startswith(NACM_API_ROOT_data)), get_nacm_api)
h2_handlers.register_handler(lambda m, p: (m == "GET") and (p.startswith(API_ROOT_data)), get_api)
h2_handlers.register_handler(lambda m, p: m == "GET", handlers.get_file)
# HTTP server init
ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
......
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 to comment