import re
import shlex
import stat
+import errno
from cmd2 import Cmd
from cmd2 import __version__ as cmd2_version
cephfs = None # holds CephFS Python bindings
shell = None # holds instance of class CephFSShell
+exit_codes = {'Misc': 1,
+ 'KeyboardInterrupt': 2,
+ errno.EPERM: 3,
+ errno.EACCES: 4,
+ errno.ENOENT: 5,
+ errno.EIO: 6,
+ errno.ENOSPC: 7,
+ errno.EEXIST: 8,
+ errno.ENODATA: 9,
+ errno.EINVAL: 10,
+ errno.EOPNOTSUPP: 11,
+ errno.ERANGE: 12,
+ errno.EWOULDBLOCK: 13,
+ errno.ENOTEMPTY: 14,
+ errno.ENOTDIR: 15,
+ errno.EDQUOT: 16,
+ errno.EPIPE: 17,
+ errno.ESHUTDOWN: 18,
+ errno.ECONNABORTED: 19,
+ errno.ECONNREFUSED: 20,
+ errno.ECONNRESET: 21,
+ errno.EINTR: 22}
+
#########################################################################
#
shell.perror(msg, **kwargs)
+def set_exit_code_msg(errcode='Misc', msg=''):
+ """
+ Set exit code and print error message
+ """
+ if isinstance(msg, libcephfs.Error):
+ shell.exit_code = exit_codes[msg.get_error_code()]
+ else:
+ shell.exit_code = exit_codes[errcode]
+ if msg:
+ perror(msg)
+
+
def mode_notation(mode):
"""
"""
continue
yield dent
except libcephfs.ObjectNotFound as e:
- perror(e)
- shell.exit_code = e.get_error_code()
+ set_exit_code_msg(msg=e)
def glob(path, pattern):
else:
try:
file_ = open(local_path, 'rb')
- except PermissionError:
- shell.exit_code = 1
- perror('error: no permission to read local file {}'.format(
- local_path.decode('utf-8')))
+ except PermissionError as e:
+ set_exit_code_msg(e.errno, 'error: no permission to read local file {}'.format(
+ local_path.decode('utf-8')))
return
stdin = 1
try:
fd = cephfs.open(remote_path, 'w', 0o666)
except libcephfs.Error as e:
- perror(e)
- shell.exit_code = 1
+ set_exit_code_msg(msg=e)
return
progress = 0
while True:
try:
argparse_args = getattr(self, 'argparse_' + command)
except AttributeError:
- self.exit_code = 1
+ set_exit_code_msg()
return None
doc_lines = getattr(
self, 'do_' + command).__doc__.expandtabs().splitlines()
self.set_prompt()
return res
except ConnectionError as e:
- perror('***\n{}'.format(e))
- self.exit_code = 3
+ set_exit_code_msg(e.errno, f'***\n{e}')
except KeyboardInterrupt:
- perror('Command aborted')
- self.exit_code = 130
+ set_exit_code_msg('KeyboardInterrupt', 'Command aborted')
except (libcephfs.Error, Exception) as e:
- perror(e)
if shell.debug:
traceback.print_exc(file=sys.stdout)
-
- if hasattr(e, 'get_error_code'):
- self.exit_code = e.get_error_code()
- else:
- # XXX: Setting it to 3 so that exceptions not stemming from
- # CephFS Python bindings can be distinguished.
- self.exit_code = 3
+ set_exit_code_msg(msg=e)
class path_to_bytes(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
try:
cephfs.mkdir(path, permission)
except libcephfs.Error as e:
- perror(e)
- self.exit_code = e.get_error_code()
+ set_exit_code_msg(e)
def complete_put(self, text, line, begidx, endidx):
"""
else:
root_dst_dir = a[0]
else:
- perror('error: no filename specified for destination')
- # TODO: perhaps, we need a more suitable retval?
- self.exit_code = 1
+ set_exit_code_msg(errno.EINVAL, 'error: no filename specified '
+ 'for destination')
return
if root_dst_dir[-1] != b'/':
if os.path.isfile(root_src_dir):
dst_file = root_dst_dir
if is_file_exists(dst_file):
- perror('{}: file exists! use --force to '
- 'overwrite'.format(dst_file.decode('utf-8')))
- self.exit_code = 1
+ set_exit_code_msg(errno.EEXIST,
+ f"{dst_file.decode('utf-8')}: file "
+ "exists! use --force to overwrite")
return
if args.local_path == b'-':
root_src_dir = b'-'
root_src_dir = cephfs.getcwd()
if args.local_path == b'-':
if args.remote_path == b'.' or args.remote_path == b'./':
- perror('error: no remote file name specified')
- self.exit_code = 1
+ set_exit_code_msg(errno.EINVAL, 'error: no remote file name specified')
return
copy_to_local(root_src_dir, b'-')
elif is_file_exists(args.remote_path):
if args.force:
pass
else:
- perror('{}: already exists! use --force to overwrite'.format(
- root_src_dir.decode('utf-8')))
- self.exit_code = e.errno
+ set_exit_code_msg(e.errno, f"{root_src_dir.decode('utf-8')}: "
+ "already exists! use --force to overwrite")
return
for file_ in files:
if not args.force:
try:
os.stat(dst_path)
- perror('{}: file already exists! use --force to '
- 'override'.format(file_.decode('utf-8')))
- self.exit_code = 1
+ set_exit_code_msg(errno.EEXIST, f"{file_.decode('utf-8')}: "
+ "file already exists! use --force to override")
return
except OSError:
copy_to_local(file_, dst_path)
try:
cephfs.rmdir(path)
except libcephfs.Error as e:
- perror(e)
- self.exit_code = e.get_error_code()
+ set_exit_code_msg(msg=e)
def complete_rm(self, text, line, begidx, endidx):
"""
cephfs.unlink(path)
except libcephfs.Error as e:
# NOTE: perhaps we need a better msg here
- perror(e)
- self.exit_code = e.get_error_code()
+ set_exit_code_msg(msg=e)
def complete_mv(self, text, line, begidx, endidx):
"""
try:
cephfs.chmod(path, mode)
except libcephfs.Error as e:
- perror(e)
- self.exit_code = e.get_error_code()
+ set_exit_code_msg(msg=e)
def complete_cat(self, text, line, begidx, endidx):
"""
if is_file_exists(path):
copy_to_local(path, b'-')
else:
- perror('{}: no such file'.format(path.decode('utf-8')))
- self.exit_code = 1
+ set_exit_code_msg(errno.ENOENT, '{}: no such file'.format(
+ path.decode('utf-8')))
umask_parser = argparse.ArgumentParser(description='Set umask value.')
umask_parser.add_argument('mode', help='Mode', type=str, action=ModeAction,
try:
os.chdir(os.path.expanduser(args.path))
except OSError as e:
- perror("Cannot change to {}: {}".format(e.filename, e.strerror))
- self.exit_code = e.errno
+ set_exit_code_msg(e.errno, "Cannot change to "
+ f"{e.filename.decode('utf-8')}: {e.strerror}")
def complete_lls(self, text, line, begidx, endidx):
"""
poutput("{}:".format(path.decode('utf-8')))
print_list(items)
except OSError as e:
- perror("'{}': {}".format(e.filename, e.strerror))
- self.exit_code = e.errno
+ set_exit_code_msg(e.errno, f"{e.filename.decode('utf-8')}: "
+ f"{e.strerror}")
# Arguments to the with_argpaser decorator function are sticky.
# The items in args.path do not get overwritten in subsequent calls.
# The arguments remain in args.paths after the function exits and we
stat.st_size, available, str(int(use)) + '%',
file.decode('utf-8')))
except libcephfs.OSError as e:
- perror("could not statfs {}: {}".format(file.decode('utf-8'),
- e.strerror))
- self.exit_code = e.get_error_code()
+ set_exit_code_msg(e.get_error_code(), "could not statfs {}: {}".format(
+ file.decode('utf-8'), e.strerror))
locate_parser = argparse.ArgumentParser(
description='Find file within file system')
poutput('{:10s} {}'.format(humansize(dusage),
f.decode('utf-8')))
except libcephfs.Error as e:
- perror(e)
- self.exit_code = e.get_error_code()
+ set_exit_code_msg(msg=e)
continue
for path in args.paths:
Quota management.
"""
if not is_dir_exists(args.path):
- perror('error: no such directory {}'.format(args.path.decode('utf-8')))
- self.exit_code = 1
+ set_exit_code_msg(errno.ENOENT, 'error: no such directory {}'.format(
+ args.path.decode('utf-8')))
return
if args.op == 'set':
if (args.max_bytes == -1) and (args.max_files == -1):
- perror('please specify either --max_bytes or --max_files or '
- 'both')
- self.exit_code = 1
+ set_exit_code_msg(errno.EINVAL, 'please specify either '
+ '--max_bytes or --max_files or both')
return
if args.max_bytes >= 0:
except libcephfs.Error as e:
cephfs.setxattr(args.path, 'ceph.quota.max_bytes',
max_bytes, os.XATTR_REPLACE)
- perror('max_bytes reset to %d' % args.max_bytes)
- self.exit_code = e.get_error_code()
+ set_exit_code_msg(e.get_error_code(), 'max_bytes reset to '
+ f'{args.max_bytes}')
if args.max_files >= 0:
max_files = to_bytes(str(args.max_files))
except libcephfs.Error as e:
cephfs.setxattr(args.path, 'ceph.quota.max_files',
max_files, os.XATTR_REPLACE)
- perror('max_files reset to %d' % args.max_files)
- self.exit_code = e.get_error_code()
+ set_exit_code_msg(e.get_error_code(), 'max_files reset to '
+ f'{args.max_files}')
elif args.op == 'get':
max_bytes = '0'
max_files = '0'
max_bytes = cephfs.getxattr(args.path, 'ceph.quota.max_bytes')
poutput('max_bytes: {}'.format(max_bytes.decode('utf-8')))
except libcephfs.Error as e:
- perror('max_bytes is not set')
- self.exit_code = e.get_error_code()
+ set_exit_code_msg(e.get_error_code(), 'max_bytes is not set')
try:
max_files = cephfs.getxattr(args.path, 'ceph.quota.max_files')
poutput('max_files: {}'.format(max_files.decode('utf-8')))
except libcephfs.Error as e:
- perror('max_files is not set')
- self.exit_code = e.get_error_code()
+ set_exit_code_msg(e.get_error_code(), 'max_files is not set')
snap_parser = argparse.ArgumentParser(description='Snapshot Management')
snap_parser.add_argument('op', type=str,
if is_dir_exists(args.dir):
cephfs.mkdir(os.path.join(args.dir, snapdir, args.name), 0o755)
else:
- self.perror("'{}': no such directory".format(
- args.dir.decode('utf-8')))
- self.exit_code = 1
+ set_exit_code_msg(errno.ENOENT, "'{}': no such directory".format(
+ args.dir.decode('utf-8')))
except libcephfs.Error as e:
- self.perror("snapshot '{}' already exists".format(
- args.name.decode('utf-8')))
- self.exit_code = e.get_error_code()
+ set_exit_code_msg(e.get_error_code(),
+ "snapshot '{}' already exists".format(
+ args.name.decode('utf-8')))
elif args.op == 'delete':
snap_dir = os.path.join(args.dir, snapdir, args.name)
try:
newargs = argparse.Namespace(paths=[snap_dir], parent=False)
self.do_rmdir_helper(newargs)
else:
- self.perror("'{}': no such snapshot".format(
+ set_exit_code_msg(errno.ENOENT, "'{}': no such snapshot".format(
args.name.decode('utf-8')))
- self.exit_code = 1
except libcephfs.Error as e:
- self.perror("error while deleting '{}'".format(
- snap_dir.decode('utf-8')))
- self.exit_code = e.get_error_code()
+ set_exit_code_msg(e.get_error_code(), "error while deleting "
+ "'{}'".format(snap_dir.decode('utf-8')))
else:
- self.perror("snapshot can only be created or deleted; check - "
- "help snap")
- self.exit_code = 1
+ set_exit_code_msg(errno.EINVAL, "snapshot can only be created or "
+ "deleted; check - help snap")
def do_help(self, line):
"""
stat.st_uid, stat.st_gid, atime,
mtime, ctime))
except libcephfs.Error as e:
- perror(e)
- self.exit_code = e.get_error_code()
+ set_exit_code_msg(msg=e)
setxattr_parser = argparse.ArgumentParser(
description='Set extended attribute for a file')
cephfs.setxattr(args.path, name_bytes, val_bytes, os.XATTR_REPLACE)
poutput('{} is successfully reset to {}'.format(args.name, args.value))
except libcephfs.Error as e:
- perror(e)
- self.exit_code = e.get_error_code()
+ set_exit_code_msg(msg=e)
getxattr_parser = argparse.ArgumentParser(
description='Get extended attribute set for a file')
poutput('{}'.format(cephfs.getxattr(args.path,
to_bytes(args.name)).decode('utf-8')))
except libcephfs.Error as e:
- perror(e)
- self.exit_code = e.get_error_code()
+ set_exit_code_msg(msg=e)
listxattr_parser = argparse.ArgumentParser(
description='List extended attributes set for a file')
else:
poutput('No extended attribute is set')
except libcephfs.Error as e:
- perror(e)
- self.exit_code = e.get_error_code()
+ set_exit_code_msg(msg=e)
#######################################################
try:
cephfs = libcephfs.LibCephFS(conffile='')
cephfs.mount()
- except libcephfs.ObjectNotFound:
+ except libcephfs.ObjectNotFound as e:
print('couldn\'t find ceph configuration not found')
- sys.exit(1)
+ sys.exit(e.get_error_code())
except libcephfs.Error as e:
print(e)
- sys.exit(1)
+ sys.exit(e.get_error_code())
def str_to_bool(val):