def mkdir(self, args): "Create a new container." session = self.get_session() cwd = session.get('cwd', '/') path = args[ARG_PATH] # Collections names should end with a '/' if not path.endswith("/"): path += '/' if not path.startswith("/"): # relative path path = "{}{}".format(cwd, path) col = Collection.find(path) if col: self.print_error(MSG_COLL_EXIST.format(path)) return parent, name = split(path) if name.startswith("cdmi_"): self.print_error(MSG_COLL_WRONG_NAME.format(name)) return p_coll = Collection.find(parent) if not p_coll: self.print_error(MSG_COLL_NOT_EXIST.format(path)) return Collection.create(name=name, container=parent)
def delete_collection(request, path): """Display the page to delete a collection""" coll = Collection.find(path) if not coll: raise Http404 if not coll.user_can(request.user, "delete"): raise PermissionDenied if request.method == "POST": parent_coll = Collection.find(coll.path) if parent_coll: parent_path = parent_coll.container else: # Just in case parent_path = "" coll.delete(username=request.user.name) messages.add_message( request, messages.INFO, u"The collection '{}' has been deleted".format(coll.name), ) return redirect("archive:view", path=parent_path) return render(request, "archive/delete.html", {"collection": coll})
def test_find(): coll1 = Collection.create("/", "a") assert Collection.find("/a") == None assert Collection.find("/a/") != None assert Collection.find("/a/", 1) == None coll1.delete()
def get_authorized_actions(self, user): """" Get available actions for a user according to the groups it belongs :param user: The user we want to check :type user: :class:`radon.model.User` :return: the set of actions the user can do :rtype: Set[str] """ # Check permission on the parent container if there's no action # defined at this level acl = self.get_acl_dict() if not acl: from radon.model import Collection parent_container = Collection.find(self.container) return parent_container.get_authorized_actions(user) actions = set([]) for gid in user.groups + ["AUTHENTICATED@"]: if gid in acl: ace = acl[gid] level = acemask_to_str(ace.acemask, True) if level == "read": actions.add("read") elif level == "write": actions.add("write") actions.add("delete") actions.add("edit") elif level == "read/write": actions.add("read") actions.add("write") actions.add("delete") actions.add("edit") return actions
def test_get_child(): # Create a new collection with a random name coll_name = uuid.uuid4().hex coll1 = Collection.create('/', coll_name) coll2 = Collection.create(coll1.path, uuid.uuid4().hex) coll3 = Collection.create(coll1.path, uuid.uuid4().hex) coll4 = Collection.create(coll1.path, uuid.uuid4().hex) resc1 = Resource.create(coll1.path, uuid.uuid4().hex, url="http://www.google.fr") resc2 = Resource.create(coll1.path, uuid.uuid4().hex, url="http://www.google.fr") coll_childs, resc_childs = coll1.get_child() assert set(coll_childs) == set([coll2.name, coll3.name, coll4.name]) assert set(resc_childs) == set([resc1.get_name(), resc2.get_name()]) assert coll1.get_child_resource_count() == 2 coll_root = Collection.find("/") # Test for a resource where the url has been lost somehow resc3 = Resource.create(coll_root.path, uuid.uuid4().hex) resc3.update(object_url=None) resc3 = Resource.find(resc3.path) coll_childs, resc_childs = coll_root.get_child() assert set(coll_childs) == set(["1/", "2/", coll1.name]) assert set(resc_childs) == set([resc3.get_name(), 'g']) coll1.delete()
def change_dir(self, args): "Move into a different container." session = self.get_session() cwd = session.get('cwd', '/') if args[ARG_PATH]: path = args[ARG_PATH] else: path = "/" if not path.startswith("/"): # relative path path = "{}{}".format(cwd, path) if not path.endswith("/"): path = path + '/' col = Collection.find(path) if not col: self.print_error(MSG_COLL_NOT_EXIST.format(path)) return session['cwd'] = path # Save the client for persistent use self.save_session(session) return 0
def read_data_object(self, path): """Read a resource""" resource = Resource.find(path) if not resource: collection = Collection.find(path) if collection: self.logger.info( u"Fail to read a resource at '{}', test if it's a collection" .format(path)) return self.read_container(path) else: self.logger.info( u"Fail to read a resource at '{}'".format(path)) return Response(status=HTTP_404_NOT_FOUND) if not resource.user_can(self.user, "read"): self.logger.warning( u"User {} tried to read resource at '{}'".format( self.user, path)) return Response(status=HTTP_403_FORBIDDEN) cdmi_resource = CDMIResource(resource, self.api_root) if self.http_mode: if cdmi_resource.is_reference(): return self.read_data_object_reference(cdmi_resource) else: return self.read_data_object_http(cdmi_resource) else: return self.read_data_object_cdmi(cdmi_resource)
def delete_resource(request, path): """Display the page to delete a resource""" resource = Resource.find(path) if not resource: raise Http404 if not resource.user_can(request.user, "delete"): raise PermissionDenied container = Collection.find(resource.container) if request.method == "POST": resource.delete(username=request.user.name) messages.add_message( request, messages.INFO, "The resource '{}' has been deleted".format(resource.name), ) return redirect("archive:view", path=container.path) # Requires delete on resource ctx = { "resource": resource, "container": container, } return render(request, "archive/resource/delete.html", ctx)
def home(request): """Default view for Activities""" notifications = Notification.recent(10) activities = [] for notif in notifications: tmpl = template.Template(notif["tmpl"]) obj_uuid = notif["object_uuid"] obj = None if notif["object_type"] == OBJ_RESOURCE: obj = Resource.find(obj_uuid) if obj: object_dict = obj.to_dict() else: object_dict = {"name": obj_uuid} elif notif["object_type"] == OBJ_COLLECTION: obj = Collection.find(obj_uuid) if obj: object_dict = obj.to_dict() else: object_dict = {"name": obj_uuid} elif notif["object_type"] == OBJ_USER: obj = User.find(obj_uuid) if obj: object_dict = obj.to_dict() else: # User has been deleted it can't be find by uuid # look in payload of the message to get the name if notif["operation"] in [OP_CREATE, OP_UPDATE]: name = notif["payload"]["post"]["name"] else: # OP_DELETE name = notif["payload"]["pre"]["name"] object_dict = {"name": name} elif notif["object_type"] == OBJ_GROUP: obj = Group.find(obj_uuid) if obj: object_dict = obj.to_dict() else: # User has been deleted it can't be find by uuid # look in payload of the message to get the name if notif["operation"] in [OP_CREATE, OP_UPDATE]: name = notif["payload"]["post"]["name"] else: # OP_DELETE name = notif["payload"]["pre"]["name"] object_dict = {"uuid": obj_uuid, "name": name} user_dict = {} if notif["username"]: user = User.find(notif["username"]) if user: user_dict = user.to_dict() else: user_dict = { 'name': notif["username"], 'email': notif["username"]+ '@radon.org' } variables = {"user": user_dict, "when": notif["when"], "object": object_dict} ctx = template.Context(variables) activities.append({"html": tmpl.render(ctx)}) return render(request, "activity/index.html", {"activities": activities})
def get_parentID(self): """Conditional Object ID of the parent container object We don't support objects only accessible by ID so this is mandatory""" parent_path = self.collection.container if self.collection.is_root: parent_path = "/" parent = Collection.find(parent_path) return parent.uuid
def put_data_object(self, path): """Put a data object to a specific collection""" # Check if a collection with the name exists collection = Collection.find(path) if collection: # Try to put a data_object when a collection of the same name # already exists self.logger.info( "Impossible to create a new resource, the collection '{}' already exists, try to update it" .format(path)) return self.put_container(path) parent, name = split(path) # Check if the resource already exists resource = Resource.find(path) # Check permissions if resource: # Update Resource if not resource.user_can(self.user, "edit"): self.logger.warning( "User {} tried to modify resource at '{}'".format( self.user, path)) return Response(status=HTTP_403_FORBIDDEN) else: # Create Resource parent_collection = Collection.find(parent) if not parent_collection: self.logger.info( "Fail to create a resource at '{}', collection doesn't exist" .format(path)) return Response(status=HTTP_404_NOT_FOUND) # Check if user can create a new resource in the collection if not parent_collection.user_can(self.user, "write"): self.logger.warning( "User {} tried to create new resource at '{}'".format( self.user, path)) return Response(status=HTTP_403_FORBIDDEN) # All permissions are checked, we can proceed to create/update if self.http_mode: return self.put_data_object_http(parent, name, resource) else: return self.put_data_object_cdmi(parent, name, resource)
def is_collection(path): """Check if the collection exists :param path: The path of the collection in Radon :type path: str :return: a boolean :rtype: bool """ from radon.model import Collection return Collection.find(path) is not None
def ls(self, args): """List a container.""" session = self.get_session() cwd = session.get('cwd', '/') if args[ARG_PATH]: path = args[ARG_PATH] if not path.startswith("/"): # relative path path = "{}{}".format(cwd, path) else: # Get the current working dir from the session file path = cwd # --v option specify the version we want to display if args["--v"]: version = int(args["--v"]) col = Collection.find(path, version) else: col = Collection.find(path) if not col: self.print_error(MSG_COLL_NOT_EXIST.format(path)) return # Display name of the collection if path == "/": print("Root:") else: print("{}:".format(col.path)) # Display Acl if args["-a"]: acl = col.get_acl_dict() if acl: for gid in acl: print(" ACL - {}: {}".format( gid, acl[gid])) else: print(" ACL: No ACE defined") # Display child c_colls, c_objs = col.get_child() for child in sorted(c_colls, key=methodcaller("lower")): print(self.terminal.blue(child)) for child in sorted(c_objs, key=methodcaller("lower")): print(child)
def edit_collection(request, path): """Display the form to edit an existing collection""" coll = Collection.find(path) if not coll: raise Http404 if not coll.user_can(request.user, "edit"): raise PermissionDenied if request.method == "POST": form = CollectionForm(request.POST) if form.is_valid(): metadata = {} for k, v in json.loads(form.cleaned_data["metadata"]): if k in metadata: if isinstance(metadata[k], list): metadata[k].append(v) else: metadata[k] = [metadata[k], v] else: metadata[k] = v try: data = form.cleaned_data coll.update(metadata=metadata, username=request.user.name) coll.create_acl_list(data["read_access"], data["write_access"]) return redirect("archive:view", path=coll.path) except CollectionConflictError: messages.add_message( request, messages.ERROR, "That name is in use in the current collection", ) else: md = coll.get_cdmi_user_meta() metadata = json.dumps(md) if not md: metadata = '{"":""}' read_access, write_access = coll.get_acl_list() initial_data = { "name": coll.name, "metadata": metadata, "read_access": read_access, "write_access": write_access, } form = CollectionForm(initial=initial_data) groups = Group.objects.all() return render( request, "archive/edit.html", {"form": form, "collection": coll, "groups": groups}, )
def test_delete_all(): coll1_name = uuid.uuid4().hex coll1 = Collection.create("/", coll1_name) coll2 = Collection.create(coll1.path, uuid.uuid4().hex) coll5 = Collection.create(coll2.path, uuid.uuid4().hex) resc1 = Resource.create(coll1.path, uuid.uuid4().hex, url="http://www.google.fr") Collection.delete_all("/{}/".format(coll1_name)) assert Collection.find(coll1_name) == None assert Collection.delete_all("/unknown/") == None
def test_delete(): coll1_name = uuid.uuid4().hex coll1 = Collection.create("/", coll1_name) coll2 = Collection.create(coll1.path, uuid.uuid4().hex) coll3 = Collection.create(coll1.path, uuid.uuid4().hex) coll4 = Collection.create(coll2.path, uuid.uuid4().hex) coll5 = Collection.create(coll4.path, uuid.uuid4().hex) resc1 = Resource.create(coll1.path, uuid.uuid4().hex, url="http://www.google.fr") coll1.delete() assert Collection.find(coll1_name) == None
def view_resource(request, path): """Display the page for a resource in the archive""" resource = Resource.find(path) if not resource: raise Http404() if not resource.user_can(request.user, "read"): raise PermissionDenied container = Collection.find(resource.container) if not container: # TODO: the container has to be there. If not it may be a network # issue with Cassandra so we try again before raising an error to the # user container = Collection.find(resource.container) if not container: return HttpResponse( status=408, content="Unable to find parent container '{}'".format( resource.container ), ) paths = [] full = "/" for pth in container.path.split("/"): if not pth: continue full = u"{}{}/".format(full, pth) paths.append((pth, full)) ctx = { "resource": resource.full_dict(request.user), "container": container, "container_path": container.path, "collection_paths": paths, } return render(request, "archive/resource/view.html", ctx)
def view_collection(request, path='/'): """Display the page which shows the subcollections/resources of a collection""" if not path: path = "/" collection = Collection.find(path) if not collection: raise Http404() if not collection.user_can(request.user, "read") and not collection.is_root: # If the user can't read, then return 404 rather than 403 so that # we don't leak information. raise Http404() paths = [] full = "/" for p in collection.path.split("/"): if not p: continue full = u"{}{}/".format(full, p) paths.append((p, full)) children_c, children_r = collection.get_child(False) children_c.sort(key=lambda x: x.lower()) children_r.sort(key=lambda x: x.lower()) ctx = { "collection": collection.to_dict(request.user), "children_c": [ Collection.find(merge(path, c)).to_dict(request.user) for c in children_c ], "children_r": [ Resource.find(merge(path, c)).simple_dict(request.user) for c in children_r ], "collection_paths": paths, "empty": len(children_c) + len(children_r) == 0, } return render(request, "archive/index.html", ctx)
def test_create_acl_fail(mocker): list_read = ['grp1'] list_write = ['grp1'] user2 = User.find("user2") # Create a new collection with a random name coll_name = uuid.uuid4().hex + "/" coll = Collection.create('/', coll_name) mocker.patch('radon.model.collection.acemask_to_str', return_value="wrong_oper") coll.create_acl_list(list_read, list_write) coll = Collection.find('/{}'.format(coll_name)) # Test get_acl_list wrong operation name acl_list = coll.get_acl_list() assert acl_list == ([], []) coll.delete() # Check authorized actions for root coll = Collection.find("/") mocker.patch.object(Collection, 'get_acl_dict', return_value=None) assert coll.get_authorized_actions(user2) == set([])
def delete_container(self, path): """Delete a container""" collection = Collection.find(path) if not collection: self.logger.info(u"Fail to delete collection at '{}'".format(path)) return Response(status=HTTP_404_NOT_FOUND) if not collection.user_can(self.user, "delete"): self.logger.warning( u"User {} tried to delete container '{}'".format( self.user, path)) return Response(status=HTTP_403_FORBIDDEN) Collection.delete_all(collection.path) self.logger.info( u"The container '{}' was successfully deleted".format(path)) return Response(status=HTTP_204_NO_CONTENT)
def test_metadata(): # Create a new collection with a random name coll_name = uuid.uuid4().hex coll1 = Collection.create('/', coll_name) metadata = {"test": "val", "test_json": '["t", "e", "s", "t"]'} coll1.update(metadata=metadata) coll1 = Collection.find("/{}/".format(coll_name)) assert coll1.get_list_user_meta() == [('test', 'val'), ('test_json', '["t", "e", "s", "t"]') ] assert coll1.get_user_meta_key("test_json") == '["t", "e", "s", "t"]' sys_meta = coll1.get_cdmi_sys_meta() assert "radon_create_ts" in sys_meta assert "radon_modify_ts" in sys_meta
def rm(self, args): """Remove a data object or a collection. """ path = args["<path>"] # Get the full path of the object to delete path = self.get_full_path(path) resc = Resource.find(path) if resc: resc.delete() return coll = Collection.find(path) if coll: coll.delete() return self.print_error(MSG_NO_OBJECT.format(path))
def read_container(self, path): """Get information on a container""" collection = Collection.find(path) if not collection: self.logger.info(u"Fail to read a collection at '{}'".format(path)) return Response(status=HTTP_404_NOT_FOUND) if not collection.user_can(self.user, "read"): self.logger.warning( u"User {} tried to read container at '{}'".format( self.user, path)) return Response(status=HTTP_403_FORBIDDEN) cdmi_container = CDMIContainer(collection, self.api_root) if self.http_mode: # HTTP Request, unsupported self.logger.warning( u"Read container '{}' using HTTP is undefined".format(path)) return Response(status=HTTP_406_NOT_ACCEPTABLE) else: # Read using CDMI return self.read_container_cdmi(cdmi_container)
def delete_data_object(self, path): """Delete a resource""" resource = Resource.find(path) if not resource: collection = Collection.find(path) if collection: self.logger.info( u"Fail to delete resource at '{}', test if it's a collection" .format(path)) return self.delete_container(path) else: self.logger.info( u"Fail to delete resource at '{}'".format(path)) return Response(status=HTTP_404_NOT_FOUND) if not resource.user_can(self.user, "delete"): self.logger.warning( u"User {} tried to delete resource '{}'".format( self.user, path)) return Response(status=HTTP_403_FORBIDDEN) resource.delete() self.logger.info( u"The resource '{}' was successfully deleted".format(path)) return Response(status=HTTP_204_NO_CONTENT)
def new_resource(request, parent): """Manage the forms to create a new resource""" parent_collection = Collection.find(parent) # Inherits perms from container by default. if not parent_collection: raise Http404() # User must be able to write to this collection if not parent_collection.user_can(request.user, "write"): raise PermissionDenied read_access, write_access = parent_collection.get_acl_list() initial = { "metadata": {}, "read_access": read_access, "write_access": write_access, } if request.method == "POST": form = ResourceNewForm(request.POST, files=request.FILES, initial=initial) if form.is_valid(): data = form.cleaned_data try: name = data["name"] metadata = {} for k, v in json.loads(data["metadata"]): if k in metadata: if isinstance(metadata[k], list): metadata[k].append(v) else: metadata[k] = [metadata[k], v] else: metadata[k] = v resource = Resource.create( container=parent_collection.path, name=name, metadata=metadata, mimetype=data["file"].content_type, creator=request.user.name, size=data["file"].size, ) res = resource.put(data["file"]) resource.create_acl_list(data["read_access"], data["write_access"]) messages.add_message( request, messages.INFO, u"New resource '{}' created".format(resource.get_name()), ) except ResourceConflictError: messages.add_message( request, messages.ERROR, "That name is in use within the current collection", ) return redirect("archive:view", path=parent_collection.path) else: form = ResourceNewForm(initial=initial) ctx = {"form": form, "container": parent_collection, "groups": Group.objects.all()} return render(request, "archive/resource/new.html", ctx)
def new_collection(request, parent): """Display the form to create a new collection""" parent_collection = Collection.find(parent) if not parent_collection.user_can(request.user, "write"): raise PermissionDenied read_access, write_access = parent_collection.get_acl_list() initial = { "metadata": {}, "read_access": read_access, "write_access": write_access, } form = CollectionNewForm(request.POST or None, initial=initial) if request.method == "POST": if form.is_valid(): data = form.cleaned_data try: name = data["name"] parent = parent_collection.path metadata = {} for k, v in json.loads(data["metadata"]): if k in metadata: if isinstance(metadata[k], list): metadata[k].append(v) else: metadata[k] = [metadata[k], v] else: metadata[k] = v collection = Collection.create( name=name, container=parent, metadata=metadata, creator=request.user.name, ) collection.create_acl_list(data["read_access"], data["write_access"]) messages.add_message( request, messages.INFO, u"New collection '{}' created".format(collection.name), ) return redirect("archive:view", path=collection.path) except CollectionConflictError: messages.add_message( request, messages.ERROR, "That name is in use in the current collection", ) except ResourceConflictError: messages.add_message( request, messages.ERROR, "That name is in use in the current collection", ) groups = Group.objects.all() return render( request, "archive/new.html", {"form": form, "parent": parent_collection, "groups": groups}, )
def edit_resource(request, path): """Display the form to edit an existing resource""" # Requires edit on resource resource = Resource.find(path) if not resource: raise Http404() container = Collection.find(resource.container) if not container: raise Http404() if not resource.user_can(request.user, "edit"): raise PermissionDenied if request.method == "POST": form = ResourceForm(request.POST) if form.is_valid(): metadata = {} for k, v in json.loads(form.cleaned_data["metadata"]): if k in metadata: if isinstance(metadata[k], list): metadata[k].append(v) else: metadata[k] = [metadata[k], v] else: metadata[k] = v try: data = form.cleaned_data resource.update(metadata=metadata, username=request.user.name) resource.create_acl_list(data["read_access"], data["write_access"]) return redirect("archive:resource_view", path=resource.path) except ResourceConflictError: messages.add_message( request, messages.ERROR, "That name is in use within the current collection", ) else: md = resource.get_cdmi_user_meta() metadata = json.dumps(md) if not md: metadata = '{"":""}' read_access, write_access = resource.get_acl_list() initial_data = { "name": resource.name, "metadata": metadata, "read_access": read_access, "write_access": write_access, } form = ResourceForm(initial=initial_data) ctx = { "form": form, "resource": resource, "container": container, "groups": Group.objects.all(), } return render(request, "archive/resource/edit.html", ctx)
def get_parentID(self): """Conditional Object ID of the parent container object We don't support objects only accessible by ID so this is mandatory""" parent = Collection.find(self.resource.container) return parent.uuid
def test_create_acl(): list_read = ['grp1'] list_write = ['grp1'] user1 = User.find("user1") user2 = User.find("user2") # Create a new collection with a random name coll_name = uuid.uuid4().hex + "/" coll = Collection.create('/', coll_name) # Test Read/Write ACL coll.create_acl_list(list_read, list_write) coll = Collection.find('/{}'.format(coll_name)) acl = coll.get_acl_dict() assert acl['grp1'].acemask == 95 acl_list = coll.get_acl_list() assert acl_list == (list_read, list_write) assert coll.get_authorized_actions(user2) == { 'edit', 'write', 'delete', 'read' } cdmi_acl = coll.get_acl_metadata() assert 'cdmi_acl' in cdmi_acl # Test Read ACL coll.create_acl_list(list_read, []) coll = Collection.find('/{}'.format(coll_name)) acl = coll.get_acl_dict() assert acl['grp1'].acemask == 9 acl_list = coll.get_acl_list() assert acl_list == (list_read, []) assert coll.get_authorized_actions(user2) == {'read'} # Test Write ACL coll.create_acl_list([], list_write) coll = Collection.find('/{}'.format(coll_name)) acl = coll.get_acl_dict() assert acl['grp1'].acemask == 86 acl_list = coll.get_acl_list() assert acl_list == ([], list_write) assert coll.get_authorized_actions(user2) == {'edit', 'write', 'delete'} # # Test the ACL metadata returned as a dictionary # acl = coll.get_acl_metadata() # assert acl['cdmi_acl'][0]['acetype'] == "ALLOW" # assert acl['cdmi_acl'][0]['identifier'] == "grp1" # assert acl['cdmi_acl'][0]['aceflags'] == 'CONTAINER_INHERIT, OBJECT_INHERIT' # assert acl['cdmi_acl'][0]['acemask'] == 'DELETE_SUBCONTAINER, WRITE_METADATA, ADD_SUBCONTAINER, ADD_OBJECT' coll.delete() # Check authorized actions for root coll = Collection.find("/") assert coll.get_authorized_actions(user1) == { 'edit', 'write', 'delete', 'read' } # Check the inheritance of the ACL # (from a collection to its parents, root in this test) coll = Collection.create('/', coll_name) assert coll.get_authorized_actions(user2) == {'read'} coll.delete()
def create(cls, container, name, url=None, metadata=None, creator=None, mimetype=None, size=None): """ Create a new resource :param container: The name of the parent collection :type container: str :param name: The name of the resource :type name: str :param url: The url of the resource :type url: str, optional :param metadata: A Key/Value pair dictionary for user metadata :type metadata: dict, optional :param creator: The name of the user who created the resource :type creator: str, optional :param mimetype: The mimetype of the resource :type mimetype: str, optional :param size: The name of the user who created the resource :type size: str, optional :return: The new Resource object :rtype: :class:`radon.model.Resource` """ from radon.model import Collection from radon.model import Notification if not container.endswith('/'): container += '/' # Make sure parent/name are not in use. path = merge(container, name) existing = cls.find(path) if existing: raise ResourceConflictError(path) # Check if parent collection exists parent = Collection.find(container) if parent is None: raise NoSuchCollectionError(container) now_date = now() if not metadata: user_meta = {} else: user_meta = {} for k in metadata: user_meta[k] = encode_meta(metadata[k]) sys_meta = { radon.cfg.meta_create_ts: encode_meta(now_date), radon.cfg.meta_modify_ts: encode_meta(now_date) } if mimetype: sys_meta[radon.cfg.meta_mimetype] = mimetype if size: sys_meta[radon.cfg.meta_size] = str(size) if not url: url = "{}{}".format(radon.cfg.protocol_cassandra, default_cdmi_id()) resc_node = TreeNode.create(container=container, name=name, user_meta=user_meta, sys_meta=sys_meta, object_url=url) if not creator: creator = radon.cfg.sys_lib_user if url.startswith(radon.cfg.protocol_cassandra): new = RadonResource(resc_node) else: new = UrlLibResource(resc_node) state = new.mqtt_get_state() payload = new.mqtt_payload({}, state) Notification.create_resource(creator, path, payload) # # Index the resource # new.index() return new