From a27ddb2871f2770690d79ddc484d5884a77e534f Mon Sep 17 00:00:00 2001 From: Anders Knutsen Date: Wed, 23 Jul 2025 10:52:28 +0200 Subject: [PATCH] V1 --- .idea/.gitignore | 3 + .idea/PBXActBackup.iml | 8 ++ .../inspectionProfiles/profiles_settings.xml | 6 ++ .idea/misc.xml | 7 ++ .idea/modules.xml | 8 ++ .idea/vcs.xml | 6 ++ SSH_SCP_Copy.py | 100 ++++++++++++++++++ readme.md | 3 + 8 files changed, 141 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/PBXActBackup.iml create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 SSH_SCP_Copy.py create mode 100644 readme.md diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/PBXActBackup.iml b/.idea/PBXActBackup.iml new file mode 100644 index 0000000..f571432 --- /dev/null +++ b/.idea/PBXActBackup.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..db8786c --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..2eabd71 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/SSH_SCP_Copy.py b/SSH_SCP_Copy.py new file mode 100644 index 0000000..a5e1e0f --- /dev/null +++ b/SSH_SCP_Copy.py @@ -0,0 +1,100 @@ +import paramiko +from scp import SCPClient +import os + +# === CONFIGURATION === +ssh_host = '192.168.130.9' +ssh_port = 22 +ssh_user = 'root' +ssh_password = '' # Or use SSH key (see notes below) +remote_folder = '/temp/bc/' +local_folder = r'C:\Backup\Telefonsentral' # Use raw string for Windows paths + +# === SETUP LOCAL FOLDER === +os.makedirs(local_folder, exist_ok=True) + +def create_ssh_client(host, port, user, password): + client = paramiko.SSHClient() + client.load_system_host_keys() + client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + client.connect(host, port, username=user, password=password) + return client + +def copy_folder(ssh_client, remote_path, local_path): + print(f"Downloading files from {remote_path} to {local_path}...") + + sftp = ssh_client.open_sftp() + + # Get all remote files + stdin, stdout, _ = ssh_client.exec_command(f"find {remote_path} -type f") + remote_files = [line.strip() for line in stdout.readlines()] + + for remote_file in remote_files: + relative_path = os.path.relpath(remote_file, remote_path).replace('/', os.sep) + local_file_path = os.path.join(local_path, relative_path) + + local_dir = os.path.dirname(local_file_path) + os.makedirs(local_dir, exist_ok=True) + + try: + print(f"Downloading {remote_file} → {local_file_path}") + sftp.get(remote_file, local_file_path) + except Exception as e: + print(f"Failed to download {remote_file}: {e}") + + sftp.close() + +def list_remote_files(ssh, path): + # Returns list of full file paths (e.g. /home/user/data/file.txt) + stdin, stdout, stderr = ssh.exec_command(f"find {path} -type f") + files = [line.strip() for line in stdout.readlines()] + return files + +def list_local_files(path): + # Returns full local file paths + local_files = [] + for dirpath, _, filenames in os.walk(path): + for f in filenames: + full_path = os.path.normpath(os.path.join(dirpath, f)) + local_files.append(full_path) + return local_files + +def sync_delete_unmatched(remote_files, local_base_path, remote_base_path): + print("Checking for stale local files to delete...") + + # Compute relative paths from remote files + remote_relative = [ + os.path.normpath(f.replace(remote_base_path, '').lstrip('/').replace('/', os.sep)) + for f in remote_files + ] + expected_local = {os.path.normpath(os.path.join(local_base_path, rel)) for rel in remote_relative} + + local_files = set(list_local_files(local_base_path)) + + to_delete = local_files - expected_local + for f in to_delete: + try: + print(f"Deleting stale file: {f}") + os.remove(f) + except Exception as e: + print(f"Failed to delete {f}: {e}") + +def main(): + try: + ssh = create_ssh_client(ssh_host, ssh_port, ssh_user, ssh_password) + + # 1. List remote files + remote_files = list_remote_files(ssh, remote_folder) + + # 2. Download all files from remote + copy_folder(ssh, remote_folder, local_folder) + + # 3. Delete local files not on remote + sync_delete_unmatched(remote_files, local_folder, remote_folder) + + ssh.close() + except Exception as e: + print(f"Error: {e}") + +if __name__ == "__main__": + main() diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..3e8cd6a --- /dev/null +++ b/readme.md @@ -0,0 +1,3 @@ +Logger på PBXAct og henter ut backups, kopierer de til MGMT maskin c:\backup\Telefonsentral + +Kjøres 1 gang pr dag via Task Scheduler i windows (A24 MGMT). \ No newline at end of file