From 413ffa12155cfd0e39fc85e4cb1818d752eacad4 Mon Sep 17 00:00:00 2001 From: Yan Cheng <58191769+yanchengnv@users.noreply.github.com> Date: Mon, 10 Jun 2024 18:41:51 -0400 Subject: [PATCH] [2.5] Support log file rotation in admin commands (#2624) * support log file rotation * apply the change to other places * add docstr --- nvflare/fuel/hci/client/fl_admin_api.py | 4 +++- nvflare/fuel/hci/cmd_arg_utils.py | 21 ++++++++++++++++++++- nvflare/private/fed/server/shell_cmd.py | 7 ++++--- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/nvflare/fuel/hci/client/fl_admin_api.py b/nvflare/fuel/hci/client/fl_admin_api.py index 68e88797c6..6ff6a63477 100644 --- a/nvflare/fuel/hci/client/fl_admin_api.py +++ b/nvflare/fuel/hci/client/fl_admin_api.py @@ -25,6 +25,7 @@ from nvflare.fuel.hci.client.api_status import APIStatus from nvflare.fuel.hci.client.fl_admin_api_constants import FLDetailKey from nvflare.fuel.hci.client.fl_admin_api_spec import APISyntaxError, FLAdminAPIResponse, FLAdminAPISpec, TargetType +from nvflare.fuel.hci.cmd_arg_utils import get_file_extension from nvflare.security.logging import secure_format_exception from .overseer_service_finder import ServiceFinderByOverseer @@ -209,7 +210,8 @@ def _validate_file_string(self, file: str) -> str: for p in paths: if p == "..": raise APISyntaxError(".. in file path is not allowed") - basename, file_extension = os.path.splitext(file) + + file_extension = get_file_extension(file) if file_extension not in [".txt", ".log", ".json", ".csv", ".sh", ".config", ".py"]: raise APISyntaxError( "this command cannot be applied to file {}. Only files with the following extensions are " diff --git a/nvflare/fuel/hci/cmd_arg_utils.py b/nvflare/fuel/hci/cmd_arg_utils.py index 1b24d71ba9..3d7f518777 100644 --- a/nvflare/fuel/hci/cmd_arg_utils.py +++ b/nvflare/fuel/hci/cmd_arg_utils.py @@ -121,10 +121,29 @@ def validate_path_string(path: str) -> str: return path +def get_file_extension(file: str) -> str: + """Get extension part of the specified file name. + If the file's name is ended with number, then the extension is before it. + + Args: + file: the file name + + Returns: extension part of the file name + + """ + parts = file.split(".") + last_part = parts[-1] + if last_part.isnumeric(): + parts.pop(-1) + file = ".".join(parts) + _, ex = os.path.splitext(file) + return ex + + def validate_file_string(file: str) -> str: """Returns the file string if it is valid.""" validate_path_string(file) - basename, file_extension = os.path.splitext(file) + file_extension = get_file_extension(file) if file_extension not in [".txt", ".log", ".json", ".csv", ".sh", ".config", ".py"]: raise SyntaxError( "this command cannot be applied to file {}. Only files with the following extensions are " diff --git a/nvflare/private/fed/server/shell_cmd.py b/nvflare/private/fed/server/shell_cmd.py index 28ef432e8f..0b82a4f889 100644 --- a/nvflare/private/fed/server/shell_cmd.py +++ b/nvflare/private/fed/server/shell_cmd.py @@ -12,12 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -import os import re import subprocess from typing import List -from nvflare.fuel.hci.cmd_arg_utils import join_args +from nvflare.fuel.hci.cmd_arg_utils import get_file_extension, join_args from nvflare.fuel.hci.conn import Connection from nvflare.fuel.hci.proto import MetaStatusValue, make_meta from nvflare.fuel.hci.reg import CommandModule, CommandModuleSpec, CommandSpec @@ -186,7 +185,9 @@ def validate_shell_command(self, args: List[str], parse_result): return ".. in path name is not allowed" if self.text_file_only: - basename, file_extension = os.path.splitext(f) + # check whether the file name is ended with numbers. If so, the actual file extension is before it. + # this is the case that when the log file (log.txt) is rotated, the previous file becomes log.txt.1. + file_extension = get_file_extension(f) if file_extension not in [".txt", ".log", ".json", ".csv", ".sh", ".config", ".py"]: return ( "this command cannot be applied to file {}. Only files with the following extensions "