Skip to content

Commit

Permalink
fix for issues: #139, #142, #143, #133, #145
Browse files Browse the repository at this point in the history
  • Loading branch information
jreadey committed Apr 11, 2023
2 parents 0d95758 + 463c960 commit 8b567dc
Show file tree
Hide file tree
Showing 15 changed files with 871 additions and 1,232 deletions.
12 changes: 0 additions & 12 deletions h5pyd/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,6 @@

from __future__ import absolute_import

#from . import _conv
#_conv.register_converters()

#from . import h5a, h5d, h5ds, h5f, h5fd, h5g, h5r, h5s, h5t, h5p, h5z

#h5s.NULL = h5s._NULL # NULL is a reserved name at the Cython layer
#h5z._register_lzf()

#from .highlevel import *

from . import version
from ._hl.base import Empty
from ._hl.h5type import special_dtype, Reference, RegionReference
Expand All @@ -40,11 +30,9 @@


from .config import Config
#from . import hsinfo
__version__ = version.version



__doc__ = \
"""
This is the h5pyd package, a Python interface to the HDF REST Server.
Expand Down
209 changes: 87 additions & 122 deletions h5pyd/_apps/hsacl.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,17 @@

cfg = Config()

#
# log error and abort app
#
def abort(msg):
logging.error(msg)
if cfg["logfile"]:
# write to stderr if we are output logs to a file
sys.stderr.write(msg + "\n")
logging.error("exiting program with return code -1")
sys.exit(-1)

#
# get given ACL, return None if not found
#
Expand All @@ -46,157 +57,118 @@ def getACL(f, username="default"):
#
# Usage
#
def printUsage():
def usage():
option_names = cfg.get_names()
cmd = cfg.get_cmd()
print("Usage:")
print("")
print("Usage: {} [options] domain [+crudep] [-crudep] [userid1 userid2 ...]".format(cfg["cmd"]))
print(f" {cmd} [options] domain [+crudep] [-crudep] [userid1 userid2 ...]")
print("")
print("Description:")
print(" Display, add, or change ACLs for a domain or folder")
print("")
print("Options:")
print(" -v | --verbose :: verbose output")
print(" -e | --endpoint <domain> :: The HDF Server endpoint, e.g. http://hsdshdflab.hdfgroup.org")
print(" -u | --user <username> :: User name credential")
print(" -p | --password <password> :: Password credential")
print(" --logfile <logfile> :: logfile path")
print(" --loglevel debug|info|warning|error :: Change log level")
print(" --bucket <bucket_name> :: Storage bucket")
print(" -h | --help :: This message.")
for name in option_names:
help_msg = cfg.get_help_message(name)
if help_msg:
print(f" {help_msg}")
print("")

print("Arguments:")
print(" domain :: Domain or Folder to be updated")
print(" +/- :: add or remove permissions")
print(" crudep :: permission flags: Create, Read, Update, Delete, rEadacl, uPdateacl")
print(" domain :: Domain or Folder to be updated")
print(" +/- :: add or remove permissions")
print(" crudep :: permission flags: Create, Read, Update, Delete, rEadacl, uPdateacl")
msg = " userid1, userid2, etc.: list of usernames, group names (group names distinguished "
msg += "by 'g:' prefix) or 'default' to set permissions for those not otherwise listed"
print(msg)
print("")
print("Examples:")
print(f" list acls: {cmd} /home/jill/myfile.h5")
print(f" list ted's acl (if any): {cmd} /home/jill/myfile.h5 ted")
print(f" add/update acl to give ted read & update permissions: {cmd} /home/jill/myfile.h5 +ru ted")
print(f" remove all permissions except read for jill: {cmd} /home/jill/myfile.h5 -cudep jill")
print(f" enable create, update, and read ACL for devs group: {cmd} /shared/datafile.h5 +cup g:devs")
print(f" enable domain and ACLs to be read by anyone: {cmd} /home/jill/myfile.h5 +re default")
print("")
print("examples...")
print("list acls: {} /home/jill/myfile.h5".format(cfg["cmd"]))
print("list ted's acl (if any): {} /home/jill/myfile.h5 ted".format(cfg["cmd"]))
print("add/update acl to give ted read & update permissions: {} /home/jill/myfile.h5 +ru ted".format(cfg["cmd"]))
print("remove all permissions except read for jill: {} /home/jill/myfile.h5 -cudep jill".format(cfg["cmd"]))
print(cfg.get_see_also(cmd))
print("")
sys.exit()



def main():
cfg["cmd"] = sys.argv[0].split('/')[-1]
if cfg["cmd"].endswith(".py"):
cfg["cmd"] = "python " + cfg["cmd"]
cfg["verbose"] = False

perm_abvr = {'c':'create', 'r': 'read', 'u': 'update', 'd': 'delete', 'e': 'readACL', 'p':'updateACL'}
fields = ('username', 'create', 'read', 'update', 'delete', 'readACL', 'updateACL')
domain = None
perm = None
loglevel = logging.ERROR
logfname = None
usernames = []
add_list = set()
remove_list = set()

if len(sys.argv) == 1 or sys.argv[1] == "-h":
printUsage()
# additional options
cfg.setitem("help", False, flags=["-h", "--help"], help="this message")

argn = 1
while argn < len(sys.argv):
arg = sys.argv[argn]
val = None
if len(sys.argv) > argn + 1:
val = sys.argv[argn+1]

try:
cmdline_args = cfg.set_cmd_flags(sys.argv[1:], allow_post_flags=True)
except ValueError as ve:
print(ve)
usage()

if len(cmdline_args) == 0:
# need a domain
usage()

if arg in ("-v", "--verbose"):
cfg["verbose"] = True
argn += 1
elif arg == "--loglevel":
val = val.upper()
if val == "DEBUG":
loglevel = logging.DEBUG
elif val == "INFO":
loglevel = logging.INFO
elif val in ("WARN", "WARNING"):
loglevel = logging.WARNING
elif val == "ERROR":
loglevel = logging.ERROR
else:
printUsage()
argn += 2
elif domain is None and arg == '--logfile':
logfname = val
argn += 2
elif domain is None and arg in ("-h", "--help"):
printUsage()
elif domain is None and arg in ("-e", "--endpoint"):
cfg["hs_endpoint"] = val
argn += 2
elif domain is None and arg in ("-u", "--username"):
cfg["hs_username"] = val
argn += 2
elif domain is None and arg in ("-p", "--password"):
cfg["hs_password"] = val
argn += 2
elif arg in ("-b", "--bucket"):
cfg["hs_bucket"] = val
argn += 2
elif domain is None and arg[0] in ('-', '+'):
print("No domain given")
printUsage()
elif domain is None:
# setup logging
logfname = cfg["logfile"]
loglevel = cfg.get_loglevel()
logging.basicConfig(filename=logfname, format='%(levelname)s %(asctime)s %(message)s', level=loglevel)
logging.debug(f"set log_level to {loglevel}")

for arg in cmdline_args:
if domain is None:
domain = arg
if domain[0] != '/':
print("Domain must start with '/'")
printUsage()
argn += 1
elif arg[0] == '+':
if len(usernames) > 0:
printUsage()
abort("no usernames given!")
add_list = set(arg[1:])
argn += 1

elif arg[0] == '-':
if len(usernames) > 0:
printUsage()
abort("remove flags must be placed before usernames!")
remove_list = set(arg[1:])
argn += 1
else:
if arg.find('/') >= 0:
print("Invalid username:", arg)
printUsage()
abort(f"invalid username: {arg}")
usernames.append(arg)
argn += 1

# setup logging
logging.basicConfig(filename=logfname, format='%(levelname)s %(asctime)s %(message)s', level=loglevel)
logging.debug("set log_level to {}".format(loglevel))

logging.info("domain: {}".format(domain))
logging.info("add_list: {}".format(add_list))
logging.info("remove_list: {}".format(remove_list))
logging.info("usernames: {}".format(usernames))
logging.info(f"domain: {domain}")
logging.info(f"add_list: {add_list}")
logging.info(f"remove_list: {remove_list}")
logging.info(f"usernames: {usernames}")

if len(usernames) == 0 and (add_list or remove_list):
print("At least one username must be given to add/remove permissions")
printUsage()
abort("at least one username must be given to add/remove permissions")

if domain is None:
print("no domain specified")
sys.exit(1)
abort("no domain specified")

conflicts = list(add_list & remove_list)

if len(conflicts) > 0:
print("permission: ", conflicts[0], " permission flag set for both add and remove")
sys.exit(1)
abort(f"permission: {conflicts[0]} flag set for both add and remove")

mode = 'r'
if add_list or remove_list:
mode = 'a' # we'll be updating the domain
perm = {}
for x in add_list:
if x not in perm_abvr:
print("Permission flag: {} is not valid - must be one of 'crudep;".format(x))
sys.exit(1)
abort("Permission flag: {x} is not valid - must be one of 'crudep'")
perm_name = perm_abvr[x]
perm[perm_name] = True
for x in remove_list:
if x not in perm_abvr:
print("Permission flag: {} is not valid - must be one of 'crudep;".format(x))
sys.exit(1)
abort(f"Permission flag: {x} is not valid - must be one of 'crudep'")
perm_name = perm_abvr[x]
perm[perm_name] = False
logging.info("perm:", perm)
Expand All @@ -209,14 +181,11 @@ def main():
f = h5pyd.File(domain, mode=mode, endpoint=cfg["hs_endpoint"], username=cfg["hs_username"], password=cfg["hs_password"], bucket=cfg["hs_bucket"])
except IOError as ioe:
if ioe.errno in (404, 410):
print("domain not found")
sys.exit(1)
abort("domain not found")
elif ioe.errno in (401, 403):
print("access is not authorized")
sys.exit(1)
abort("access is not authorized")
else:
print("Unexpected error:", ioe)
sys.exit(1)
abort(f"Unexpected error: {ioe}")

# update/add ACL if permission flags have been set
if perm:
Expand All @@ -243,18 +212,17 @@ def main():
if acl is None:
acl = default_acl.copy()
acl["userName"] = username
logging.info("updating acl to: {}".format(acl))
logging.info(f"updating acl to: {acl}")
# mix in any permission changes
for k in perm:
acl[k] = perm[k]
try:
f.putACL(acl)
except IOError as ioe:
if ioe.errno in (401, 403):
print("access is not authorized")
abort("access is not authorized")
else:
print("Unexpected error:", ioe)
sys.exit(1)
abort("Unexpected error:", ioe)
#
# read the acls
#
Expand All @@ -264,13 +232,12 @@ def main():
acls = f.getACLs()
except IOError as ioe:
if ioe.errno == 403:
print("User {} does not have permission to read ACL for this domain".format(cfg["hs_username"]))
sys.exit(1)
username = cfg["hs_username"]
abort(f"User: {username} does not have permission to read ACL for this domain")
elif ioe.errno == 401:
print("username/password needs to be provided")
sys.exit(1)
abort("username/password needs to be provided")
else:
print("Unexpected error: {}".format(ioe))
abort(f"Unexpected error: {ioe}")
print("%015s %08s %08s %08s %08s %08s %08s " % fields)
print("-"*80)
for acl in acls:
Expand All @@ -289,16 +256,14 @@ def main():
print("%015s %08s %08s %08s %08s %08s %08s " % vals)
except IOError as ioe:
if ioe.errno == 403:
print("User {} does not have permission to read ACL for this domain".format(cfg["hs_username"]))
sys.exit(1)
this_user = cfg["hs_username"]
abort(f"User {this_user} does not have permission to read ACL for this domain")
elif ioe.errno == 401:
print("username/password needs to be provided")
sys.exit(1)
abort("username/password needs to be provided")
elif ioe.errno == 404:
print(username, "<NONE>")
abort(f"{username} not found")
else:
print("Unexpected error:", ioe)
sys.exit(1)
abort(f"Unexpected error: {ioe}")

f.close()

Expand Down
Loading

0 comments on commit 8b567dc

Please sign in to comment.