diff --git a/abst/__version__.py b/abst/__version__.py index d9180eb..4fe5a76 100644 --- a/abst/__version__.py +++ b/abst/__version__.py @@ -10,7 +10,7 @@ "CLI Command making OCI Bastion and kubernetes usage simple and fast" ) -__version__ = "2.3.4" +__version__ = "2.3.5" __author__ = "Jiri Otoupal" __author_email__ = "jiri-otoupal@ips-database.eu" __license__ = "MIT" diff --git a/abst/cli_commands/cp_cli/commands.py b/abst/cli_commands/cp_cli/commands.py index a9f3b9e..1ee5300 100644 --- a/abst/cli_commands/cp_cli/commands.py +++ b/abst/cli_commands/cp_cli/commands.py @@ -1,13 +1,14 @@ import logging import os import re +from pathlib import Path from subprocess import call import click import rich from InquirerPy import inquirer -from abst.utils.misc_funcs import setup_calls, fetch_pods +from abst.utils.misc_funcs import setup_calls, fetch_pods, recursive_copy @click.group("cp", help="Copy commands for special usage") @@ -50,11 +51,12 @@ def cp_secret( @cp.command("file", help="Will copy file into pod with containing string name") -@click.argument("pod_name") -@click.argument("local_path") -@click.argument("dest_path") +@click.argument("pod_name", type=str) +@click.argument("local_path", type=str) +@click.argument("dest_path", type=str) +@click.option("--exclude", default="", type=str) @click.option("--debug", is_flag=True, default=False) -def cp_to_pod(pod_name, local_path, dest_path, debug): +def cp_to_pod(pod_name, local_path, dest_path, exclude, debug): setup_calls(debug) try: @@ -94,11 +96,11 @@ def cp_to_pod(pod_name, local_path, dest_path, debug): rich.print("[red]Failed to copy using conventional kubectl cp, probably missing [yellow]tar[/yellow] " "executable[/red]") rich.print("[yellow]Trying alternative copy method...[/yellow]") - kubectl_alt_copy_cmd = (f"cat {local_path} |" - f" kubectl exec -i {pod_name_precise} -n {data[0]} -- tee {dest_path} > /dev/null") - logging.info(f"Executing {kubectl_alt_copy_cmd}") - exit_code = os.system(kubectl_alt_copy_cmd) - if exit_code == 0: - rich.print("[green]File successfully copied![/green]") else: - rich.print("[red]Failed.[/red]") + return + local_path_obj = Path(local_path).expanduser().resolve() + thread_list = [] + recursive_copy(local_path_obj, dest_path, exclude, data, pod_name_precise, thread_list) + + for t in thread_list: + t.join() diff --git a/abst/utils/misc_funcs.py b/abst/utils/misc_funcs.py index 8d566d7..f785e79 100644 --- a/abst/utils/misc_funcs.py +++ b/abst/utils/misc_funcs.py @@ -1,7 +1,10 @@ import json import logging +import os import subprocess from pathlib import Path +from threading import Thread +from time import sleep from typing import Optional import rich @@ -63,3 +66,53 @@ def fetch_pods(): .split("\n") ) return pod_lines + + +def recursive_copy(dir_to_iter: Path, dest_path: str, exclude: str, data: list, pod_name_precise: str, + thread_list: list): + for file in dir_to_iter.iterdir(): + final_dest_path = make_final_dest_path(dest_path, file) + if file.name == exclude: + rich.print(f" [yellow]{file} excluded.[/yellow]") + continue + elif file.is_dir(): + rich.print(f"[yellow]Recursion to folder {file}[/yellow]") + + create_folder_kubectl(data, final_dest_path, pod_name_precise) + t = Thread(name=f"recursive_copy_{file}", target=recursive_copy, + args=[file, dest_path, exclude, data, pod_name_precise, thread_list]) + t.start() + thread_list.append(t) + else: + copy_file_alt_kubectl(data, final_dest_path, file, pod_name_precise) + + +def make_final_dest_path(dest_path, file): + sub_path = str(file).split("/") + + fsp = sub_path[sub_path.index(Path(dest_path).name) + 1:] + + final_dest_path = f"{dest_path}{'/' if len(fsp) > 0 else ''}{'/'.join(fsp)}" + return final_dest_path + + +def create_folder_kubectl(data: list, dest_path: str, pod_name_precise: str): + kubectl_create_dir_cmd = (f"kubectl" + f" exec -i {pod_name_precise} -n {data[0]} -- mkdir -p \"{dest_path}\"") + logging.info(f"Executing {kubectl_create_dir_cmd}") + os.system(kubectl_create_dir_cmd) + + +def copy_file_alt_kubectl(data: list, dest_path: str, local_path: Path, pod_name_precise: str, tries=4): + kubectl_alt_copy_cmd = (f"cat \"{local_path}\" |" + f" kubectl exec -i {pod_name_precise} -n {data[0]} -- tee \"{dest_path}\" > /dev/null") + logging.info(f"Executing {kubectl_alt_copy_cmd}") + exit_code = subprocess.call(kubectl_alt_copy_cmd, shell=True) + rich.print(f" [green]{local_path.name} ({local_path.stat().st_size / 1000} kB) successfully copied![/green]") + if exit_code != 0 and tries < 0: + rich.print("[red]Failed to copy.[/red]") + exit(1) + elif exit_code != 0 and tries > 0: + rich.print(f"Failed to copy will try again, try {tries}/4") + sleep(5) + copy_file_alt_kubectl(data, dest_path, local_path, pod_name_precise, tries - 1)