async def GET_Group(request): """HTTP method to return JSON for group""" log.request(request) app = request.app params = request.rel_url.query h5path = None getAlias = False include_links = False include_attrs = False group_id = request.match_info.get('id') if not group_id and "h5path" not in params: # no id, or path provided, so bad request msg = "Missing group id" log.warn(msg) raise HTTPBadRequest(reason=msg) if group_id: log.info(f"GET_Group, id: {group_id}") # is the id a group id and not something else? if not isValidUuid(group_id, "Group"): msg = f"Invalid group id: {group_id}" log.warn(msg) raise HTTPBadRequest(reason=msg) if "getalias" in params: if params["getalias"]: getAlias = True if "h5path" in params: h5path = params["h5path"] if not group_id and h5path[0] != '/': msg = "h5paths must be absolute if no parent id is provided" log.warn(msg) raise HTTPBadRequest(reason=msg) log.info(f"GET_Group, h5path: {h5path}") if "include_links" in params and params["include_links"]: include_links = True if "include_attrs" in params and params["include_attrs"]: include_attrs = True username, pswd = getUserPasswordFromRequest(request) if username is None and app['allow_noauth']: username = "******" else: await validateUserPassword(app, username, pswd) domain = getDomainFromRequest(request) if not isValidDomain(domain): msg = f"Invalid domain: {domain}" log.warn(msg) raise HTTPBadRequest(reason=msg) bucket = getBucketForDomain(domain) if h5path and h5path[0] == '/': # ignore the request path id (if given) and start # from root group for absolute paths domain_json = await getDomainJson(app, domain) if "root" not in domain_json: msg = f"Expected root key for domain: {domain}" log.warn(msg) raise HTTPBadRequest(reason=msg) group_id = domain_json["root"] if h5path: group_id = await getObjectIdByPath(app, group_id, h5path, bucket=bucket ) # throws 404 if not found if not isValidUuid(group_id, "Group"): msg = f"No group exist with the path: {h5path}" log.warn(msg) raise HTTPNotFound() log.info(f"get group_id: {group_id} from h5path: {h5path}") # verify authorization to read the group await validateAction(app, domain, group_id, username, "read") # get authoritative state for group from DN (even if it's in the meta_cache). group_json = await getObjectJson(app, group_id, refresh=True, include_links=include_links, include_attrs=include_attrs, bucket=bucket) log.debug(f"domain from request: {domain}") group_json["domain"] = getPathForDomain(domain) if bucket: group_json["bucket"] = bucket if getAlias: root_id = group_json["root"] alias = [] if group_id == root_id: alias.append('/') else: idpath_map = {root_id: '/'} h5path = await getPathForObjectId(app, root_id, idpath_map, tgt_id=group_id, bucket=bucket) if h5path: alias.append(h5path) group_json["alias"] = alias hrefs = [] group_uri = '/groups/' + group_id hrefs.append({'rel': 'self', 'href': getHref(request, group_uri)}) hrefs.append({ 'rel': 'links', 'href': getHref(request, group_uri + '/links') }) root_uri = '/groups/' + group_json["root"] hrefs.append({'rel': 'root', 'href': getHref(request, root_uri)}) hrefs.append({'rel': 'home', 'href': getHref(request, '/')}) hrefs.append({ 'rel': 'attributes', 'href': getHref(request, group_uri + '/attributes') }) group_json["hrefs"] = hrefs resp = await jsonResponse(request, group_json) log.response(request, resp=resp) return resp
async def GET_AttributeValue(request): """HTTP method to return an attribute value""" log.request(request) app = request.app log.info("GET_AttributeValue") collection = getRequestCollectionName(request) # returns datasets|groups|datatypes obj_id = request.match_info.get('id') if not obj_id: msg = "Missing object id" log.warn(msg) raise HTTPBadRequest(reason=msg) if not isValidUuid(obj_id, obj_class=collection): msg = f"Invalid object id: {obj_id}" log.warn(msg) raise HTTPBadRequest(reason=msg) attr_name = request.match_info.get('name') validateAttributeName(attr_name) username, pswd = getUserPasswordFromRequest(request) if username is None and app['allow_noauth']: username = "******" else: await validateUserPassword(app, username, pswd) domain = getDomainFromRequest(request) if not isValidDomain(domain): msg = f"Invalid domain value: {domain}" log.warn(msg) raise HTTPBadRequest(reason=msg) bucket = getBucketForDomain(domain) # get domain JSON domain_json = await getDomainJson(app, domain) if "root" not in domain_json: log.error(f"Expected root key for domain: {domain}") raise HTTPBadRequest(reason="Unexpected Error") # TBD - verify that the obj_id belongs to the given domain await validateAction(app, domain, obj_id, username, "read") req = getDataNodeUrl(app, obj_id) req += '/' + collection + '/' + obj_id + "/attributes/" + attr_name log.debug("get Attribute: " + req) params = {} if bucket: params["bucket"] = bucket dn_json = await http_get(app, req, params=params) log.debug("got attributes json from dn for obj_id: " + str(dn_json)) attr_shape = dn_json["shape"] log.debug(f"attribute shape: {attr_shape}") if attr_shape["class"] == 'H5S_NULL': msg = "Null space attributes can not be read" log.warn(msg) raise HTTPBadRequest(reason=msg) accept_type = getAcceptType(request) response_type = accept_type # will adjust later if binary not possible type_json = dn_json["type"] shape_json = dn_json["shape"] item_size = getItemSize(type_json) if item_size == 'H5T_VARIABLE' and accept_type != "json": msg = "Client requested binary, but only JSON is supported for variable length data types" log.info(msg) response_type = "json" if response_type == "binary": arr_dtype = createDataType(type_json) # np datatype np_shape = getShapeDims(shape_json) try: arr = jsonToArray(np_shape, arr_dtype, dn_json["value"]) except ValueError: msg = "Bad Request: input data doesn't match selection" log.warn(msg) raise HTTPBadRequest(reason=msg) output_data = arr.tobytes() log.debug(f"GET AttributeValue - returning {len(output_data)} bytes binary data") # write response try: resp = StreamResponse() resp.content_type = "application/octet-stream" resp.content_length = len(output_data) # allow CORS resp.headers['Access-Control-Allow-Origin'] = '*' resp.headers['Access-Control-Allow-Methods'] = "GET, POST, DELETE, PUT, OPTIONS" resp.headers['Access-Control-Allow-Headers'] = "Content-Type, api_key, Authorization" await resp.prepare(request) await resp.write(output_data) except Exception as e: log.error(f"Got exception: {e}") raise HTTPInternalServerError() finally: await resp.write_eof() else: resp_json = {} if "value" in dn_json: resp_json["value"] = dn_json["value"] hrefs = [] obj_uri = '/' + collection + '/' + obj_id attr_uri = obj_uri + '/attributes/' + attr_name hrefs.append({'rel': 'self', 'href': getHref(request, attr_uri)}) hrefs.append({'rel': 'home', 'href': getHref(request, '/')}) hrefs.append({'rel': 'owner', 'href': getHref(request, obj_uri)}) resp_json["hrefs"] = hrefs resp = await jsonResponse(request, resp_json) log.response(request, resp=resp) return resp
async def GET_Dataset(request): """HTTP method to return JSON description of a dataset""" log.request(request) app = request.app params = request.rel_url.query include_attrs = False h5path = None getAlias = False dset_id = request.match_info.get('id') if not dset_id and "h5path" not in params: msg = "Missing dataset id" log.warn(msg) raise HTTPBadRequest(reason=msg) if "include_attrs" in params and params["include_attrs"]: include_attrs = True if dset_id: if not isValidUuid(dset_id, "Dataset"): msg = f"Invalid dataset id: {dset_id}" log.warn(msg) raise HTTPBadRequest(reason=msg) if "getalias" in params: if params["getalias"]: getAlias = True else: group_id = None if "grpid" in params: group_id = params["grpid"] if not isValidUuid(group_id, "Group"): msg = f"Invalid parent group id: {group_id}" log.warn(msg) raise HTTPBadRequest(reason=msg) if "h5path" not in params: msg = "Expecting either ctype id or h5path url param" log.warn(msg) raise HTTPBadRequest(reason=msg) h5path = params["h5path"] if not group_id and h5path[0] != '/': msg = "h5paths must be absolute" log.warn(msg) raise HTTPBadRequest(reason=msg) log.info(f"GET_Dataset, h5path: {h5path}") username, pswd = getUserPasswordFromRequest(request) if username is None and app['allow_noauth']: username = "******" else: await validateUserPassword(app, username, pswd) domain = getDomainFromRequest(request) if not isValidDomain(domain): msg = f"Invalid domain: {domain}" log.warn(msg) raise HTTPBadRequest(reason=msg) bucket = getBucketForDomain(domain) verbose = False if "verbose" in params and params["verbose"]: verbose = True if h5path: if group_id is None: domain_json = await getDomainJson(app, domain) if "root" not in domain_json: msg = f"Expected root key for domain: {domain}" log.warn(msg) raise HTTPBadRequest(reason=msg) group_id = domain_json["root"] dset_id = await getObjectIdByPath(app, group_id, h5path, bucket=bucket ) # throws 404 if not found if not isValidUuid(dset_id, "Dataset"): msg = f"No dataset exist with the path: {h5path}" log.warn(msg) raise HTTPNotFound() log.info(f"get dataset_id: {dset_id} from h5path: {h5path}") # get authoritative state for dataset from DN (even if it's in the meta_cache). dset_json = await getObjectJson(app, dset_id, refresh=True, include_attrs=include_attrs, bucket=bucket) # check that we have permissions to read the object await validateAction(app, domain, dset_id, username, "read") log.debug(f"got dset_json: {dset_json}") resp_json = {} resp_json["id"] = dset_json["id"] resp_json["root"] = dset_json["root"] resp_json["shape"] = dset_json["shape"] resp_json["type"] = dset_json["type"] if "creationProperties" in dset_json: resp_json["creationProperties"] = dset_json["creationProperties"] else: resp_json["creationProperties"] = {} if "layout" in dset_json: resp_json["layout"] = dset_json["layout"] resp_json["attributeCount"] = dset_json["attributeCount"] resp_json["created"] = dset_json["created"] resp_json["lastModified"] = dset_json["lastModified"] resp_json["domain"] = getPathForDomain(domain) if getAlias: root_id = dset_json["root"] alias = [] idpath_map = {root_id: '/'} h5path = await getPathForObjectId(app, root_id, idpath_map, tgt_id=dset_id, bucket=bucket) if h5path: alias.append(h5path) resp_json["alias"] = alias if include_attrs: resp_json["attributes"] = dset_json["attributes"] hrefs = [] dset_uri = '/datasets/' + dset_id hrefs.append({'rel': 'self', 'href': getHref(request, dset_uri)}) root_uri = '/groups/' + dset_json["root"] hrefs.append({'rel': 'root', 'href': getHref(request, root_uri)}) hrefs.append({'rel': 'home', 'href': getHref(request, '/')}) hrefs.append({ 'rel': 'attributes', 'href': getHref(request, dset_uri + '/attributes') }) # provide a value link if the dataset is relatively small, # otherwise create a preview link that shows a limited number of data values dset_shape = dset_json["shape"] if dset_shape["class"] != 'H5S_NULL': count = 1 if dset_shape["class"] == 'H5S_SIMPLE': dims = dset_shape["dims"] count = getNumElements(dims) if count <= 100: # small number of values, provide link to entire dataset hrefs.append({ 'rel': 'data', 'href': getHref(request, dset_uri + '/value') }) else: # large number of values, create preview link previewQuery = getPreviewQuery(dset_shape["dims"]) hrefs.append({ 'rel': 'preview', 'href': getHref(request, dset_uri + '/value', query=previewQuery) }) resp_json["hrefs"] = hrefs if verbose: # get allocated size and num_chunks for the dataset if available dset_detail = await getDatasetDetails(app, dset_id, dset_json["root"], bucket=bucket) if dset_detail is not None: if "num_chunks" in dset_detail: resp_json["num_chunks"] = dset_detail["num_chunks"] if "allocated_bytes" in dset_detail: resp_json["allocated_size"] = dset_detail["allocated_bytes"] if "lastModified" in dset_detail: resp_json["lastModified"] = dset_detail["lastModified"] resp = await jsonResponse(request, resp_json) log.response(request, resp=resp) return resp
async def GET_Attribute(request): """HTTP method to return JSON for an attribute""" log.request(request) app = request.app collection = getRequestCollectionName(request) # returns datasets|groups|datatypes obj_id = request.match_info.get('id') if not obj_id: msg = "Missing object id" log.warn(msg) raise HTTPBadRequest(reason=msg) if not isValidUuid(obj_id, obj_class=collection): msg = f"Invalid object id: {obj_id}" log.warn(msg) raise HTTPBadRequest(reason=msg) attr_name = request.match_info.get('name') validateAttributeName(attr_name) username, pswd = getUserPasswordFromRequest(request) if username is None and app['allow_noauth']: username = "******" else: await validateUserPassword(app, username, pswd) domain = getDomainFromRequest(request) if not isValidDomain(domain): msg = f"Invalid domain: {domain}" log.warn(msg) raise HTTPBadRequest(reason=msg) bucket = getBucketForDomain(domain) # TBD - verify that the obj_id belongs to the given domain await validateAction(app, domain, obj_id, username, "read") req = getDataNodeUrl(app, obj_id) req += '/' + collection + '/' + obj_id + "/attributes/" + attr_name log.debug("get Attribute: " + req) params = {} if bucket: params["bucket"] = bucket dn_json = await http_get(app, req, params=params) log.debug("got attributes json from dn for obj_id: " + str(obj_id)) resp_json = {} resp_json["name"] = attr_name resp_json["type"] = dn_json["type"] resp_json["shape"] = dn_json["shape"] if "value" in dn_json: resp_json["value"] = dn_json["value"] resp_json["created"] = dn_json["created"] # attributes don't get modified, so use created timestamp as lastModified resp_json["lastModified"] = dn_json["created"] hrefs = [] obj_uri = '/' + collection + '/' + obj_id attr_uri = obj_uri + '/attributes/' + attr_name hrefs.append({'rel': 'self', 'href': getHref(request, attr_uri)}) hrefs.append({'rel': 'home', 'href': getHref(request, '/')}) hrefs.append({'rel': 'owner', 'href': getHref(request, obj_uri)}) resp_json["hrefs"] = hrefs resp = await jsonResponse(request, resp_json) log.response(request, resp=resp) return resp
async def GET_Attributes(request): """HTTP method to return JSON for attribute collection""" log.request(request) app = request.app params = request.rel_url.query collection = getRequestCollectionName(request) # returns datasets|groups|datatypes obj_id = request.match_info.get('id') if not obj_id: msg = "Missing object id" log.warn(msg) raise HTTPBadRequest(reason=msg) if not isValidUuid(obj_id, obj_class=collection): msg = "Invalid obj id: {}".format(obj_id) log.warn(msg) raise HTTPBadRequest(reason=msg) include_data = False if "IncludeData" in params and params["IncludeData"]: include_data = True limit = None if "Limit" in params: try: limit = int(params["Limit"]) except ValueError: msg = "Bad Request: Expected int type for limit" log.warn(msg) raise HTTPBadRequest(reason=msg) marker = None if "Marker" in params: marker = params["Marker"] username, pswd = getUserPasswordFromRequest(request) if username is None and app['allow_noauth']: username = "******" else: await validateUserPassword(app, username, pswd) domain = getDomainFromRequest(request) if not isValidDomain(domain): msg = f"Invalid domain: {domain}" log.warn(msg) raise HTTPBadRequest(reason=msg) bucket = getBucketForDomain(domain) # TBD - verify that the obj_id belongs to the given domain await validateAction(app, domain, obj_id, username, "read") req = getDataNodeUrl(app, obj_id) req += '/' + collection + '/' + obj_id + "/attributes" params = {} if limit is not None: params["Limit"] = str(limit) if marker is not None: params["Marker"] = marker if include_data: params["IncludeData"] = '1' if bucket: params["bucket"] = bucket log.debug(f"get attributes: {req}") dn_json = await http_get(app, req, params=params) log.debug(f"got attributes json from dn for obj_id: {obj_id}") attributes = dn_json["attributes"] # mixin hrefs for attribute in attributes: attr_name = attribute["name"] attr_href = '/' + collection + '/' + obj_id + '/attributes/' + attr_name attribute["href"] = getHref(request, attr_href) resp_json = {} resp_json["attributes"] = attributes hrefs = [] obj_uri = '/' + collection + '/' + obj_id hrefs.append({'rel': 'self', 'href': getHref(request, obj_uri + '/attributes')}) hrefs.append({'rel': 'home', 'href': getHref(request, '/')}) hrefs.append({'rel': 'owner', 'href': getHref(request, obj_uri)}) resp_json["hrefs"] = hrefs resp = await jsonResponse(request, resp_json) log.response(request, resp=resp) return resp
async def GET_Domain(request): """HTTP method to return JSON for given domain""" log.request(request) app = request.app params = request.rel_url.query (username, pswd) = getUserPasswordFromRequest(request) if username is None and app['allow_noauth']: username = "******" else: await validateUserPassword(app, username, pswd) domain = None try: domain = getDomainFromRequest(request) except ValueError: log.warn(f"Invalid domain: {domain}") raise HTTPBadRequest(reason="Invalid domain name") bucket = getBucketForDomain(domain) log.debug(f"GET_Domain domain: {domain} bucket: {bucket}") if not bucket and not config.get("bucket_name"): # no bucket defined, raise 400 msg = "Bucket not provided" log.warn(msg) raise HTTPBadRequest(reason=msg) verbose = False if "verbose" in params and params["verbose"]: verbose = True if not domain: log.info("no domain passed in, returning all top-level domains") # no domain passed in, return top-level domains for this request domains = await get_domains(request) rsp_json = {"domains": domains} rsp_json["hrefs"] = [] resp = await jsonResponse(request, rsp_json) log.response(request, resp=resp) return resp log.info(f"got domain: {domain}") domain_json = await getDomainJson(app, domain, reload=True) if domain_json is None: log.warn(f"domain: {domain} not found") raise HTTPNotFound() if 'owner' not in domain_json: log.error("No owner key found in domain") raise HTTPInternalServerError() if 'acls' not in domain_json: log.error("No acls key found in domain") raise HTTPInternalServerError() log.debug(f"got domain_json: {domain_json}") # validate that the requesting user has permission to read this domain aclCheck(domain_json, "read", username) # throws exception if not authorized if "h5path" in params: # if h5path is passed in, return object info for that path # (if exists) h5path = params["h5path"] root_id = domain_json["root"] obj_id = await getObjectIdByPath(app, root_id, h5path, bucket=bucket ) # throws 404 if not found log.info(f"get obj_id: {obj_id} from h5path: {h5path}") # get authoritative state for object from DN (even if it's in the meta_cache). obj_json = await getObjectJson(app, obj_id, refresh=True, bucket=bucket) obj_json["domain"] = domain # Not bothering with hrefs for h5path lookups... resp = await jsonResponse(request, obj_json) log.response(request, resp=resp) return resp # return just the keys as per the REST API rsp_json = await get_domain_response(app, domain_json, bucket=bucket, verbose=verbose) # include domain objects if requested if "getobjs" in params and params["getobjs"] and "root" in domain_json: root_id = domain_json["root"] include_attrs = False if "include_attrs" in params and params["include_attrs"]: include_attrs = True domain_objs = await getDomainObjects(app, root_id, include_attrs=include_attrs, bucket=bucket) rsp_json["domain_objs"] = domain_objs hrefs = [] hrefs.append({'rel': 'self', 'href': getHref(request, '/')}) if "root" in domain_json: root_uuid = domain_json["root"] hrefs.append({ 'rel': 'database', 'href': getHref(request, '/datasets') }) hrefs.append({'rel': 'groupbase', 'href': getHref(request, '/groups')}) hrefs.append({ 'rel': 'typebase', 'href': getHref(request, '/datatypes') }) hrefs.append({ 'rel': 'root', 'href': getHref(request, '/groups/' + root_uuid) }) hrefs.append({'rel': 'acls', 'href': getHref(request, '/acls')}) parent_domain = getParentDomain(domain) if not parent_domain or getPathForDomain(parent_domain) == '/': is_toplevel = True else: is_toplevel = False log.debug(f"href parent domain: {parent_domain}") if not is_toplevel: hrefs.append({ 'rel': 'parent', 'href': getHref(request, '/', domain=parent_domain) }) rsp_json["hrefs"] = hrefs resp = await jsonResponse(request, rsp_json) log.response(request, resp=resp) return resp
async def GET_ACL(request): """HTTP method to return JSON for given domain/ACL""" log.request(request) app = request.app acl_username = request.match_info.get('username') if not acl_username: msg = "Missing username for ACL" log.warn(msg) raise HTTPBadRequest(reason=msg) (username, pswd) = getUserPasswordFromRequest(request) if username is None and app['allow_noauth']: username = "******" else: await validateUserPassword(app, username, pswd) try: domain = getDomainFromRequest(request) except ValueError: msg = "Invalid domain" log.warn(msg) raise HTTPBadRequest(reason=msg) # use reload to get authoritative domain json try: domain_json = await getDomainJson(app, domain, reload=True) except ClientResponseError as ce: if ce.code in (404, 410): msg = "domain not found" log.warn(msg) raise HTTPNotFound() else: log.error(f"unexpected error: {ce.code}") raise HTTPInternalServerError() # validate that the requesting user has permission to read ACLs in this domain if acl_username in (username, "default"): # allow read access for a users on ACL, or default aclCheck(domain_json, "read", username) # throws exception if not authorized else: aclCheck(domain_json, "readACL", username) # throws exception if not authorized if 'owner' not in domain_json: log.warn("No owner key found in domain") raise HTTPInternalServerError() if 'acls' not in domain_json: log.warn("No acls key found in domain") raise HTTPInternalServerError() acls = domain_json["acls"] log.debug(f"got domain_json: {domain_json}") if acl_username not in acls: msg = f"acl for username: [{acl_username}] not found" log.warn(msg) raise HTTPNotFound() acl = acls[acl_username] acl_rsp = {} for k in acl.keys(): acl_rsp[k] = acl[k] acl_rsp["userName"] = acl_username # return just the keys as per the REST API rsp_json = {} rsp_json["acl"] = acl_rsp hrefs = [] hrefs.append({'rel': 'self', 'href': getHref(request, '/acls')}) if "root" in domain_json: hrefs.append({ 'rel': 'root', 'href': getHref(request, '/groups/' + domain_json["root"]) }) hrefs.append({'rel': 'home', 'href': getHref(request, '/')}) hrefs.append({'rel': 'owner', 'href': getHref(request, '/')}) rsp_json["hrefs"] = hrefs resp = await jsonResponse(request, rsp_json) log.response(request, resp=resp) return resp
async def GET_Datatypes(request): """HTTP method to return datatype collection for given domain""" log.request(request) app = request.app params = request.rel_url.query (username, pswd) = getUserPasswordFromRequest(request) if username is None and app['allow_noauth']: username = "******" else: await validateUserPassword(app, username, pswd) try: domain = getDomainFromRequest(request) except ValueError: msg = "Invalid domain" log.warn(msg) raise HTTPBadRequest(reason=msg) # use reload to get authoritative domain json try: domain_json = await getDomainJson(app, domain, reload=True) except ClientResponseError as ce: if ce.code in (404, 410): msg = "domain not found" log.warn(msg) raise HTTPNotFound() else: log.error(f"Unexpected Error: {ce.code})") raise HTTPInternalServerError() if 'owner' not in domain_json: log.error("No owner key found in domain") raise HTTPInternalServerError() if 'acls' not in domain_json: log.error("No acls key found in domain") raise HTTPInternalServerError() log.debug(f"got domain_json: {domain_json}") # validate that the requesting user has permission to read this domain aclCheck(domain_json, "read", username) # throws exception if not authorized limit = None if "Limit" in params: try: limit = int(params["Limit"]) except ValueError: msg = "Bad Request: Expected int type for limit" log.warn(msg) raise HTTPBadRequest(reason=msg) marker = None if "Marker" in params: marker = params["Marker"] # get the datatype collection list obj_ids = [] if "root" in domain_json or domain_json["root"]: # get the groups collection list collections = await get_collections(app, domain_json["root"]) objs = collections["datatypes"] obj_ids = getIdList(objs, marker=marker, limit=limit) # create hrefs hrefs = [] hrefs.append({'rel': 'self', 'href': getHref(request, '/datatypes')}) if "root" in domain_json: root_uuid = domain_json["root"] hrefs.append({ 'rel': 'root', 'href': getHref(request, '/groups/' + root_uuid) }) hrefs.append({'rel': 'home', 'href': getHref(request, '/')}) # return obj ids and hrefs rsp_json = {} rsp_json["datatypes"] = obj_ids rsp_json["hrefs"] = hrefs resp = await jsonResponse(request, rsp_json) log.response(request, resp=resp) return resp
async def GET_ACLs(request): """HTTP method to return JSON for domain/ACLs""" log.request(request) app = request.app (username, pswd) = getUserPasswordFromRequest(request) if username is None and app['allow_noauth']: username = "******" else: await validateUserPassword(app, username, pswd) try: domain = getDomainFromRequest(request) except ValueError: msg = "Invalid domain" log.warn(msg) raise HTTPBadRequest(message=msg) # use reload to get authoritative domain json try: domain_json = await getDomainJson(app, domain, reload=True) except ClientResponseError: log.warn("domain not found") log.warn(msg) raise HTTPNotFound() if 'owner' not in domain_json: log.error("No owner key found in domain") raise HTTPInternalServerError() if 'acls' not in domain_json: log.error("No acls key found in domain") raise HTTPInternalServerError() acls = domain_json["acls"] log.debug(f"got domain_json: {domain_json}") # validate that the requesting user has permission to read this domain aclCheck(domain_json, "readACL", username) # throws exception if not authorized acl_list = [] acl_usernames = list(acls.keys()) acl_usernames.sort() for acl_username in acl_usernames: entry = {"userName": acl_username} acl = acls[acl_username] for k in acl.keys(): entry[k] = acl[k] acl_list.append(entry) # return just the keys as per the REST API rsp_json = {} rsp_json["acls"] = acl_list hrefs = [] hrefs.append({'rel': 'self', 'href': getHref(request, '/acls')}) if "root" in domain_json: hrefs.append({ 'rel': 'root', 'href': getHref(request, '/groups/' + domain_json["root"]) }) hrefs.append({'rel': 'home', 'href': getHref(request, '/')}) hrefs.append({'rel': 'owner', 'href': getHref(request, '/')}) rsp_json["hrefs"] = hrefs resp = await jsonResponse(request, rsp_json) log.response(request, resp=resp) return resp
async def GET_Datatype(request): """HTTP method to return JSON for committed datatype""" log.request(request) app = request.app params = request.rel_url.query include_attrs = False h5path = None getAlias = False ctype_id = request.match_info.get('id') if not ctype_id and "h5path" not in params: msg = "Missing type id" log.warn(msg) raise HTTPBadRequest(reason=msg) if "include_attrs" in params and params["include_attrs"]: include_attrs = True if ctype_id: if not isValidUuid(ctype_id, "Type"): msg = "Invalid type id: {}".format(ctype_id) log.warn(msg) raise HTTPBadRequest(reason=msg) if "getalias" in params: if params["getalias"]: getAlias = True else: group_id = None if "grpid" in params: group_id = params["grpid"] if not isValidUuid(group_id, "Group"): msg = "Invalid parent group id: {}".format(group_id) log.warn(msg) raise HTTPBadRequest(reason=msg) if "h5path" not in params: msg = "Expecting either ctype id or h5path url param" log.warn(msg) raise HTTPBadRequest(reason=msg) h5path = params["h5path"] if h5path[0] != '/' and group_id is None: msg = "h5paths must be absolute" log.warn(msg) raise HTTPBadRequest(reason=msg) log.info("GET_Datatype, h5path: {}".format(h5path)) username, pswd = getUserPasswordFromRequest(request) if username is None and app['allow_noauth']: username = "******" else: await validateUserPassword(app, username, pswd) domain = getDomainFromRequest(request) if not isValidDomain(domain): msg = "Invalid host value: {}".format(domain) log.warn(msg) raise HTTPBadRequest(reason=msg) if h5path: domain_json = await getDomainJson(app, domain) if "root" not in domain_json: msg = "Expected root key for domain: {}".format(domain) log.warn(msg) raise HTTPBadRequest(reason=msg) if group_id is None: group_id = domain_json["root"] ctype_id = await getObjectIdByPath(app, group_id, h5path) # throws 404 if not found if not isValidUuid(ctype_id, "Datatype"): msg = "No datatype exist with the path: {}".format(h5path) log.warn(msg) raise HTTPGone() log.info("got ctype_id: {} from h5path: {}".format(ctype_id, h5path)) await validateAction(app, domain, ctype_id, username, "read") # get authoritative state for group from DN (even if it's in the meta_cache). type_json = await getObjectJson(app, ctype_id, refresh=True, include_attrs=include_attrs) type_json["domain"] = domain if getAlias: root_id = type_json["root"] alias = [] idpath_map = {root_id: '/'} h5path = await getPathForObjectId(app, root_id, idpath_map, tgt_id=ctype_id) if h5path: alias.append(h5path) type_json["alias"] = alias hrefs = [] ctype_uri = '/datatypes/'+ctype_id hrefs.append({'rel': 'self', 'href': getHref(request, ctype_uri)}) root_uri = '/groups/' + type_json["root"] hrefs.append({'rel': 'root', 'href': getHref(request, root_uri)}) hrefs.append({'rel': 'home', 'href': getHref(request, '/')}) hrefs.append({'rel': 'attributes', 'href': getHref(request, ctype_uri+'/attributes')}) type_json["hrefs"] = hrefs resp = await jsonResponse(request, type_json) log.response(request, resp=resp) return resp
async def GET_Links(request): """HTTP method to return JSON for link collection""" log.request(request) app = request.app params = request.rel_url.query group_id = request.match_info.get('id') if not group_id: msg = "Missing group id" log.warn(msg) raise HTTPBadRequest(reason=msg) if not isValidUuid(group_id, obj_class="Group"): msg = f"Invalid group id: {group_id}" log.warn(msg) raise HTTPBadRequest(reason=msg) limit = None if "Limit" in params: try: limit = int(params["Limit"]) except ValueError: msg = "Bad Request: Expected int type for limit" log.warn(msg) raise HTTPBadRequest(reason=msg) marker = None if "Marker" in params: marker = params["Marker"] username, pswd = getUserPasswordFromRequest(request) if username is None and app['allow_noauth']: username = "******" else: await validateUserPassword(app, username, pswd) domain = getDomainFromRequest(request) if not isValidDomain(domain): msg = f"domain: {domain}" log.warn(msg) raise HTTPBadRequest(reason=msg) bucket = getBucketForDomain(domain) await validateAction(app, domain, group_id, username, "read") req = getDataNodeUrl(app, group_id) req += "/groups/" + group_id + "/links" query_sep = '?' if limit is not None: req += query_sep + "Limit=" + str(limit) query_sep = '&' if marker is not None: req += query_sep + "Marker=" + marker log.debug("get LINKS: " + req) params = {} if bucket: params["bucket"] = bucket links_json = await http_get(app, req, params=params) log.debug(f"got links json from dn for group_id: {group_id}") links = links_json["links"] # mix in collection key, target and hrefs for link in links: if link["class"] == "H5L_TYPE_HARD": collection_name = getCollectionForId(link["id"]) link["collection"] = collection_name target_uri = '/' + collection_name + '/' + link["id"] link["target"] = getHref(request, target_uri) link_uri = '/groups/' + group_id + '/links/' + link['title'] link["href"] = getHref(request, link_uri) resp_json = {} resp_json["links"] = links hrefs = [] group_uri = '/groups/' + group_id hrefs.append({ 'rel': 'self', 'href': getHref(request, group_uri + '/links') }) hrefs.append({'rel': 'home', 'href': getHref(request, '/')}) hrefs.append({'rel': 'owner', 'href': getHref(request, group_uri)}) resp_json["hrefs"] = hrefs resp = await jsonResponse(request, resp_json) log.response(request, resp=resp) return resp
async def GET_Link(request): """HTTP method to return JSON for a group link""" log.request(request) app = request.app group_id = request.match_info.get('id') if not group_id: msg = "Missing group id" log.warn(msg) raise HTTPBadRequest(reason=msg) if not isValidUuid(group_id, obj_class="Group"): msg = f"Invalid group id: {group_id}" log.warn(msg) raise HTTPBadRequest(reason=msg) link_title = request.match_info.get('title') validateLinkName(link_title) username, pswd = getUserPasswordFromRequest(request) if username is None and app['allow_noauth']: username = "******" else: await validateUserPassword(app, username, pswd) domain = getDomainFromRequest(request) if not isValidDomain(domain): msg = f"Invalid domain: {domain}" log.warn(msg) raise HTTPBadRequest(reason=msg) bucket = getBucketForDomain(domain) await validateAction(app, domain, group_id, username, "read") req = getDataNodeUrl(app, group_id) req += "/groups/" + group_id + "/links/" + link_title log.debug("get LINK: " + req) params = {} if bucket: params["bucket"] = bucket link_json = await http_get(app, req, params=params) log.debug("got link_json: " + str(link_json)) resp_link = {} resp_link["title"] = link_title link_class = link_json["class"] resp_link["class"] = link_class if link_class == "H5L_TYPE_HARD": resp_link["id"] = link_json["id"] resp_link["collection"] = getCollectionForId(link_json["id"]) elif link_class == "H5L_TYPE_SOFT": resp_link["h5path"] = link_json["h5path"] elif link_class == "H5L_TYPE_EXTERNAL": resp_link["h5path"] = link_json["h5path"] resp_link["h5domain"] = link_json["h5domain"] else: log.warn(f"Unexpected link class: {link_class}") resp_json = {} resp_json["link"] = resp_link resp_json["created"] = link_json["created"] # links don't get modified, so use created timestamp as lastModified resp_json["lastModified"] = link_json["created"] hrefs = [] group_uri = '/groups/' + group_id hrefs.append({ 'rel': 'self', 'href': getHref(request, group_uri + '/links/' + link_title) }) hrefs.append({'rel': 'home', 'href': getHref(request, '/')}) hrefs.append({'rel': 'owner', 'href': getHref(request, group_uri)}) if link_json["class"] == "H5L_TYPE_HARD": target = '/' + resp_link["collection"] + '/' + resp_link["id"] hrefs.append({'rel': 'target', 'href': getHref(request, target)}) resp_json["hrefs"] = hrefs resp = await jsonResponse(request, resp_json) log.response(request, resp=resp) return resp