From ab6fa1d6b838e21dbe026ccb090c5080a8ee61bb Mon Sep 17 00:00:00 2001 From: Kyr Shatskyy Date: Mon, 20 Jul 2020 15:16:32 +0200 Subject: [PATCH] orchestra.remote: add move_file, copy_file and read_file Signed-off-by: Kyr Shatskyy --- teuthology/misc.py | 18 ++----- teuthology/orchestra/remote.py | 88 ++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 13 deletions(-) diff --git a/teuthology/misc.py b/teuthology/misc.py index b66e78c0ca..547709fd64 100644 --- a/teuthology/misc.py +++ b/teuthology/misc.py @@ -624,7 +624,7 @@ def remove_lines_from_file(remote, path, line_is_valid_test, on when the main site goes up and down. """ # read in the specified file - in_data = get_file(remote, path, False).decode() + in_data = remote.read_file(path, False).decode() out_data = "" first_line = True @@ -667,17 +667,9 @@ def prepend_lines_to_file(remote, path, lines, sudo=False): """ temp_file_path = remote.mktemp() - - data = get_file(remote, path, sudo).decode() - - # add the additional data and write it back out, using a temp file - # in case of connectivity of loss, and then mv it to the - # actual desired location - data = lines + data - write_file(remote, temp_file_path, data) - - # then do a 'mv' to the actual file location - move_file(remote, temp_file_path, path, sudo) + remote.write_file(temp_file_path, lines) + remote.copy_file(path, temp_file_path, append=True, sudo=sudo) + remote.move_file(temp_file_path, path, sudo=sudo) def create_file(remote, path, data="", permissions=str(644), sudo=False): @@ -773,7 +765,7 @@ def get_scratch_devices(remote): """ devs = [] try: - file_data = get_file(remote, "/scratch_devs").decode() + file_data = remote.read_file("/scratch_devs").decode() devs = file_data.split() except Exception: devs = remote.sh('ls /dev/[sv]d?').strip().split('\n') diff --git a/teuthology/orchestra/remote.py b/teuthology/orchestra/remote.py index 2dbfbdd483..84d39862d6 100644 --- a/teuthology/orchestra/remote.py +++ b/teuthology/orchestra/remote.py @@ -458,6 +458,94 @@ class Remote(object): ]) return self.run(args=args, wait=False, stdout=run.PIPE) + def copy_file(self, src, dst, sudo=False, mode=None, owner=None, + mkdir=False, append=False): + """ + Copy data to remote file + + :param src: source file path on remote host + :param dst: destination file path on remote host + :param sudo: use sudo to write file, defaults False + :param mode: set file mode bits if provided + :param owner: set file owner if provided + :param mkdir: ensure the destination directory exists, defaults False + :param append: append data to the file, defaults False + """ + dd = 'sudo dd' if sudo else 'dd' + args = dd + ' if=' + src + ' of=' + dst + if append: + args += ' conv=notrunc oflag=append' + if mkdir: + mkdirp = 'sudo mkdir -p' if sudo else 'mkdir -p' + dirpath = os.path.dirname(dst) + if dirpath: + args = mkdirp + ' ' + dirpath + '\n' + args + if mode: + chmod = 'sudo chmod' if sudo else 'chmod' + args += '\n' + chmod + ' ' + mode + ' ' + dst + if owner: + chown = 'sudo chown' if sudo else 'chown' + args += '\n' + chown + ' ' + owner + ' ' + dst + args = 'set -ex' + '\n' + args + self.run(args=args) + + def move_file(self, src, dst, sudo=False, mode=None, owner=None, + mkdir=False): + """ + Move data to remote file + + :param src: source file path on remote host + :param dst: destination file path on remote host + :param sudo: use sudo to write file, defaults False + :param mode: set file mode bits if provided + :param owner: set file owner if provided + :param mkdir: ensure the destination directory exists, defaults False + """ + mv = 'sudo mv' if sudo else 'mv' + args = mv + ' ' + src + ' ' + dst + if mkdir: + mkdirp = 'sudo mkdir -p' if sudo else 'mkdir -p' + dirpath = os.path.dirname(dst) + if dirpath: + args = mkdirp + ' ' + dirpath + '\n' + args + if mode: + chmod = 'sudo chmod' if sudo else 'chmod' + args += ' && ' + chmod + ' ' + mode + ' ' + dst + if owner: + chown = 'sudo chown' if sudo else 'chown' + args += ' && ' + chown + ' ' + owner + ' ' + dst + self.run(args=args) + + def read_file(self, path, sudo=False, stdout=None, + offset=0, length=0): + """ + Read data from remote file + + :param path: file path on remote host + :param sudo: use sudo to read the file, defaults False + :param stdout: output object, defaults to io.BytesIO() + :param offset: number of bytes to skip from the file + :param length: number of bytes to read from the file + """ + dd = 'sudo dd' if sudo else 'dd' + args = dd + ' if=' + path + ' of=/dev/stdout' + iflags=[] + # we have to set defaults here instead of the method's signature, + # because python is reusing the object from call to call + stdout = stdout or BytesIO() + if offset: + args += ' skip=' + str(offset) + iflags += 'skip_bytes' + if length: + args += ' count=' + str(length) + iflags += 'count_bytes' + if iflags: + args += ' iflag=' + ','.join(iflags) + args = 'set -ex' + '\n' + args + proc = self.run(args=args, stdout=stdout) + return proc.stdout.getvalue() + + def write_file(self, path, data, sudo=False, mode=None, owner=None, mkdir=False, append=False): """ -- 2.39.5