Skip to content

Instantly share code, notes, and snippets.

@mietzen
Created January 8, 2025 17:42
Show Gist options
  • Save mietzen/5fa04c4e5c0f8fb780c5082e5cac4936 to your computer and use it in GitHub Desktop.
Save mietzen/5fa04c4e5c0f8fb780c5082e5cac4936 to your computer and use it in GitHub Desktop.
Python Script for transfering files into a Proxmox VM
#!/bin/python3
import sys
import subprocess
import os
import json
import time
def read_in_chunks(file_path, chunk_size):
"""Reads a file in chunks of the specified size."""
with open(file_path, 'rb') as file: # Open in binary mode to handle all file types
while chunk := file.read(chunk_size):
yield chunk
def print_progress_bar(iteration, total, elapsed_time, transferred_bytes, length=50):
"""Prints a progress bar with transfer rate to the console."""
percent = f"{100 * (iteration / float(total)):.1f}"
filled_length = int(length * iteration // total)
bar = '=' * filled_length + '-' * (length - filled_length)
rate = transferred_bytes / (1024 * elapsed_time) if elapsed_time > 0 else 0 # MB/s
print(f"\rProgress: |{bar}| {percent}% Complete | {rate:.2f} KB/s", end="\r")
if iteration == total:
print() # Move to a new line on completion
# Example usage
vmid = sys.argv[1]
file_in = sys.argv[2]
file_out = sys.argv[3]
chunk_size = (1024 * 1024) - 1 # 1 MiB - 1 Byte
file_size = os.path.getsize(file_in) # Get the total file size
total_chunks = (file_size + chunk_size - 1) // chunk_size # Calculate the total number of chunks
operator = '>'
current_chunk = 0
transferred_bytes = 0
start_time = time.time()
print_progress_bar(current_chunk, total_chunks, 0, transferred_bytes)
for chunk in read_in_chunks(file_in, chunk_size):
try:
# Call the system command with subprocess and pipe the chunk data
cmd = ["qm", "guest", "exec", vmid, "--pass-stdin", "1", "--", "sh", "-c", f"cat {operator} {file_out}"]
if os.getuid() != 0:
cmd = ["sudo"] + cmd
process = subprocess.run(cmd,
input=chunk, # Provide the chunk as stdin to the command
text=False, # Ensures binary mode for input
stdout=subprocess.PIPE, # Capture stdout
stderr=subprocess.PIPE, # Capture stderr
check=True # Raises an exception if the command fails
)
operator = '>>'
if not process.stdout or process.stderr:
print(process.stdout.decode())
print(process.stderr.decode())
sys.exit(1)
stdout_json = json.loads(process.stdout.decode())
if stdout_json['exitcode'] != 0 or stdout_json['exited'] != 1:
print(process.stdout.decode())
print(process.stderr.decode())
sys.exit(1)
except subprocess.CalledProcessError as e:
print(f"An error occurred: {e}")
sys.exit(1)
current_chunk += 1
transferred_bytes += len(chunk)
elapsed_time = time.time() - start_time
print_progress_bar(current_chunk, total_chunks, elapsed_time, transferred_bytes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment