def test_copy_tar(self, valid_config): responses.add( responses.PUT, "http://pbench.example.com/api/v1/upload/ctrl/controller", status=200, ) crt = CopyResultTb("controller", tarball, self.config, self.logger) crt.copy_result_tb("token")
def test_copy_tar(self, valid_config): tbname = os.path.basename(tarball) responses.add( responses.PUT, f"http://pbench.example.com/api/v1/upload/{tbname}", status=HTTPStatus.OK, ) crt = CopyResultTb("controller", tarball, self.config, self.logger) crt.copy_result_tb("token")
def test_copy_tar(self, valid_config): responses.add(responses.POST, "http://pbench.example.com/api/v1/upload", status=200) try: crt = CopyResultTb(tarball, self.config, self.logger) crt.copy_result_tb() except SystemExit: assert False else: assert True
def test_bad_tar(self, caplog, valid_config): responses.add( responses.PUT, "http://pbench.example.com/api/v1/upload/ctrl/controller", status=200, ) expected_error_message = ( f"FileNotFoundError: Tarball '{bad_tarball}' does not exist") caplog.set_level(logging.ERROR, logger=self.logger.name) with pytest.raises(FileNotFoundError) as e: crt = CopyResultTb("controller", bad_tarball, self.config, self.logger) crt.copy_result_tb("token") assert str(e).endswith(expected_error_message)
def test_bad_tar(self, caplog, valid_config): responses.add(responses.POST, "http://pbench.example.com/api/v1/upload", status=200) expected_error_message = f"tarball does not exist, '{bad_tarball}'" caplog.set_level(logging.ERROR, logger=self.logger.name) try: crt = CopyResultTb(bad_tarball, self.config, self.logger) crt.copy_result_tb() except SystemExit: assert caplog.records assert len(caplog.records) == 1 assert caplog.records[0].message == expected_error_message else: assert False
def test_multiple_files(self, caplog, valid_config): responses.add(responses.POST, "http://pbench.example.com/api/v1/upload", status=200) caplog.set_level(logging.ERROR, logger=self.logger.name) base_dir = os.path.dirname(tarball) with NamedTemporaryFile(suffix=".add", dir=base_dir): expected_error_message = f"(internal): unexpected file count, 3, associated with tarball, '{tarball}'" try: crt = CopyResultTb(tarball, self.config, self.logger) crt.copy_result_tb() except SystemExit: assert caplog.records assert len(caplog.records) == 1 assert caplog.records[0].message == expected_error_message else: assert False
def test_missing_md5(self, caplog, valid_config): responses.add(responses.POST, "http://pbench.example.com/api/v1/upload", status=200) caplog.set_level(logging.ERROR, logger=self.logger.name) with NamedTemporaryFile(suffix=".tar.xz") as missing_md5_tar: expected_error_message = ( f"tarball's .md5 does not exist, '{missing_md5_tar.name}.md5'") try: crt = CopyResultTb(missing_md5_tar.name, self.config, self.logger) crt.copy_result_tb() except SystemExit: assert caplog.records assert len(caplog.records) == 1 assert caplog.records[0].message == expected_error_message else: assert False
def move_results(ctx, _user, _prefix, _show_server): config = PbenchAgentConfig(ctx["args"]["config"]) logger = get_pbench_logger("pbench", config) controller = os.environ.get("_pbench_full_hostname") if not controller: logger.error("Missing controller name (should be 'hostname -f' value)") sys.exit(1) results_webserver = config.results.get("webserver") if not results_webserver: logger.error( "No web server host configured from which we can fetch the FQDN of the host to which we copy/move results" ) logger.debug("'webserver' variable in 'results' section not set") server_rest_url = config.results.get("server_rest_url") response = requests.get(f"{server_rest_url}/host_info") if response.status_code not in [200, 201]: logger.error( "Unable to determine results host info from %s/host_info", server_rest_url ) sys.exit(1) if response.text.startswith("MESSAGE"): message = response.text.split("===")[1] logger.info("*** Message from sysadmins of %s:", results_webserver) logger.info("***\n*** %s", message) logger.info("***\n*** No local actions taken.") sys.exit(1) results_path_prefix = response.text.split(":")[1] if not results_path_prefix: logger.error( "fetch results host info did not contain a path prefix: %s", response.text ) sys.exit(1) try: temp_dir = tempfile.mkdtemp( dir=config.pbench_tmp, prefix="pbench-move-results." ) except Exception: logger.error("Failed to create temporary directory") sys.exit(1) runs_copied = 0 failures = 0 for dirent in config.pbench_run.iterdir(): if not dirent.is_dir(): continue if dirent.name.startswith("tools-") or dirent.name == "tmp": continue result_dir = dirent mrt = MakeResultTb(result_dir, temp_dir, _user, _prefix, config, logger) result_tb_name = mrt.make_result_tb() assert ( result_tb_name ), "Logic bomb! make_result_tb() always returns a tar ball name" crt = CopyResultTb(controller, result_tb_name, config, logger) crt.copy_result_tb() try: # We always remove the constructed tar ball, regardless of success # or failure, since we keep the result directory below on failure. os.remove(result_tb_name) os.remove(f"{result_tb_name}.md5") except OSError: logger.error("rm failed to remove %s and its .md5 file", result_tb_name) sys.exit(1) try: shutil.rmtree(result_dir) except OSError: logger.error("rm failed to remove the %s directory hierarchy", result_dir) sys.exit(1) runs_copied += 1 if runs_copied + failures > 0: logger.debug( "successfully moved %s runs, encountered %s failures", runs_copied, failures ) return runs_copied, failures
def move_results(ctx, _user, _prefix, _show_server): config = PbenchAgentConfig(ctx["args"]["config"]) logger = get_pbench_logger("pbench-move-results", config) controller = os.environ.get("full_hostname") if not controller: logger.error("Missing controller name (should be 'hostname -f' value)") sys.exit(1) results_webserver = config.results.get("webserver") if not results_webserver: logger.error( "No web server host configured from which we can fetch the FQDN of the host to which we copy/move results" ) logger.debug("'webserver' variable in 'results' section not set") if not _user: _user = config.agent.get("pbench_user") server_rest_url = config.results.get("server_rest_url") response = requests.get(f"{server_rest_url}/host_info") if response.status_code not in [200, 201]: logger.error("Unable to determine results host info from %s/host_info", server_rest_url) sys.exit(1) if response.text.startswith("MESSAGE"): message = response.text.split("===")[1] logger.info("*** Message from sysadmins of %s:", results_webserver) logger.info("***\n*** %s", message) logger.info("***\n*** No local actions taken.") sys.exit(1) results_path_prefix = response.text.split(":")[1] if not results_path_prefix: logger.error( "fetch results host info did not contain a path prefix: %s", response.text) sys.exit(1) runs_copied = 0 failures = 0 try: temp_dir = tempfile.mkdtemp(dir=config.pbench_tmp, prefix="pbench-move-results.") except Exception: logger.error("Failed to create temporary directory") sys.exit(1) dirs = [ _dir for _dir in next(os.walk(config.pbench_run))[1] if not _dir.startswith("tools-") and not _dir.startswith("tmp") ] for _dir in dirs: result_dir = config.pbench_run / _dir mrt = MakeResultTb(result_dir, temp_dir, _user, _prefix, config, logger) result_tb_name = mrt.make_result_tb() if result_tb_name: crt = CopyResultTb(controller, result_tb_name, config, logger) copy_result = crt.copy_result_tb() try: os.remove(result_tb_name) os.remove(f"{result_tb_name}.md5") except OSError: logger.error("rm failed to remove %s and its .md5 file", result_tb_name) sys.exit(1) if not copy_result: failures += 1 continue try: os.remove(result_dir) except OSError: logger.error("rm failed to remove the %s directory hierarchy", result_dir) sys.exit(1) runs_copied += 1 if runs_copied + failures > 0: logger.debug("successfully moved %s runs, encountered %s failures", runs_copied, failures) return failures
def execute(self) -> int: logger = get_pbench_logger("pbench-agent", self.config) temp_dir = tempfile.mkdtemp(dir=self.config.pbench_tmp, prefix="pbench-move-results.") runs_copied = 0 failures = 0 no_of_tb = 0 for dirent in self.config.pbench_run.iterdir(): if not dirent.is_dir(): continue if dirent.name.startswith("tools-") or dirent.name == "tmp": continue no_of_tb += 1 result_dir = dirent try: mrt = MakeResultTb(result_dir, temp_dir, self.config, logger) except FileNotFoundError as e: logger.error("File Not Found Error, {}", e) continue except NotADirectoryError as e: logger.error("Bad Directory, {}", e) continue try: result_tb_name = mrt.make_result_tb() except BadMDLogFormat as e: logger.warning("Bad Metadata.log file encountered, {}", e) failures += 1 continue except FileNotFoundError as e: logger.debug("File Not Found error, {}", e) failures += 1 continue except RuntimeError as e: logger.warning("Unexpected Error encountered, {}", e) failures += 1 continue except Exception as e: logger.debug("Unexpected Error occurred, {}", e) failures += 1 continue try: crt = CopyResultTb(self.context.controller, result_tb_name, self.config, logger) except FileNotFoundError as e: logger.error("File Not Found error, {}", e) failures += 1 continue try: crt.copy_result_tb(self.context.token) except (FileUploadError, RuntimeError) as e: logger.error("Error uploading a file, {}", e) failures += 1 continue try: # We always remove the constructed tar ball, regardless of success # or failure, since we keep the result directory below on failure. os.remove(result_tb_name) except OSError: logger.error("Failed to remove {}", result_tb_name) failures += 1 continue try: shutil.rmtree(result_dir) except OSError: logger.error("Failed to remove the {} directory hierarchy", result_dir) failures += 1 continue runs_copied += 1 logger.info( "Status: Total no. of tarballs {}, Successfully moved {}, Encountered {} failures", no_of_tb, runs_copied, failures, ) return 0
def execute(self) -> int: logger = get_pbench_logger("pbench-agent", self.config) crt = CopyResultTb(self.context.controller, self.context.result_tb_name, self.config, logger) crt.copy_result_tb(self.context.token) return 0