#!/usr/bin/env python3
import os
import requests
import json
import urllib.parse
import argparse
def read_api_token(file_path):
with open(file_path, 'r') as f:
line = f.readline().strip()
key, value = line.split(': ', 1)
return {key: value}
def read_config_file(config_file):
if config_file:
with open(config_file, 'r') as f:
return json.load(f)
return {}
def get_import_data(pve_node, esxi_name, datastore_name, vmname, headers):
url = f"https://localhost:8006/api2/json/nodes/{pve_node}/storage/{esxi_name}/import-metadata"
params = {
"volume": f"ha-datacenter/{datastore_name}/{vmname}/{vmname}.vmx"
}
response = requests.get(url, params=params, headers=headers, verify=False)
return response.json()
def get_next_vmid(headers):
url = "https://localhost:8006/api2/json/cluster/nextid"
response = requests.get(url, headers=headers, verify=False)
return response.json()['data']
def process_import_data(import_data, tag, pve_storagename, vmid, config):
data = import_data['data']
name = data['create-args']['name']
result = []
net_replacement = config.get('network_replacement', {})
disk_iothread = config.get('disk_iothread', '')
disk_params = config.get('disk_params', '')
result.append('cpu=Broadwell-noTSX')
result.append(f'vmid={vmid}')
for key, value in data['create-args'].items():
if isinstance(value, (int, float)):
value = str(value)
if "media=cdrom" in value:
value = "file=" + value
if key=='scsihw':
value = config.get('scsihw_replacement', value)
value = urllib.parse.quote(value)
result.append(f'{key}={value}')
for key, value in data['net'].items():
model = net_replacement.get(value['model'], value['model'])
value_str = f"{model}={value['macaddr']},bridge=vmbr0,tag={tag}"
encoded_value = urllib.parse.quote(value_str)
result.append(f'{key}={encoded_value}')
for key, value in data['disks'].items():
volid_index = value['volid'].rindex(name)
volid_suffix = value['volid'][volid_index:]
disk_value = f"{pve_storagename}:{vmid}/{volid_suffix}"
if disk_params:
disk_value += f",{disk_params}"
if key.startswith('scsi') and disk_iothread!='':
disk_value += f',{disk_iothread}'
encoded_disk_value = urllib.parse.quote(disk_value)
result.append(f'{key}={encoded_disk_value}')
result_str = '&'.join(result)
return result_str
def create_directory(path):
os.makedirs(path, exist_ok=True)
def process_vmdk_files(source_base_dir, target_directory, vmname):
source_path = os.path.join(source_base_dir, vmname)
relative_path = os.path.relpath(source_path,target_directory)
print(relative_path)
for root, _, files in os.walk(source_path):
for file in files:
if file.endswith(".vmdk") and not any(exclude in file for exclude in ["-flat", "-ctk"]):
file_path = os.path.join(root, file)
with open(file_path, 'r') as f:
content = f.read()
# Replace for VMFS lines
new_content = content.replace(f'VMFS "{vmname}', f'VMFS "{relative_path}/{vmname}')
# Replace for changeTrackPath lines
new_content = new_content.replace(f'changeTrackPath="{vmname}', f'changeTrackPath="{relative_path}/{vmname}')
target_file_path = os.path.join(target_directory, file)
with open(target_file_path, 'w') as f:
f.write(new_content)
def main():
parser = argparse.ArgumentParser(description="Proxmox VM import script")
parser.add_argument("--vmname", required=True, help="Name of the VM")
parser.add_argument("--vlan_tag", required=True, help="VLAN Tag for network interfaces")
parser.add_argument("--pve_node", required=True, help="Proxmox VE node name")
parser.add_argument("--esxi_name", required=True, help="ESXi server name")
parser.add_argument("--datastore_name", required=True, help="Datastore name")
parser.add_argument("--pve_storagename", required=True, help="Proxmox storage name")
parser.add_argument("--pve_storagepathprefix", required=True, help="Proxmox storage path prefix")
parser.add_argument("--api_token_file", required=True, help="Path to curl header file containing API token")
parser.add_argument("--config", help="Path to JSON config file for replacements and additions")
args = parser.parse_args()
headers = read_api_token(args.api_token_file)
config = read_config_file(args.config)
import_data = get_import_data(args.pve_node, args.esxi_name, args.datastore_name, args.vmname, headers)
vmid = get_next_vmid(headers)
print(f"VMID: {vmid}")
vm_config = process_import_data(import_data, args.vlan_tag, args.pve_storagename, vmid, config)
print(f"VM Config: {vm_config}")
target_directory = f"{args.pve_storagepathprefix}/{args.pve_storagename}/images/{vmid}"
create_directory(target_directory)
source_base_dir = os.path.join("/mnt", args.esxi_name, args.datastore_name)
process_vmdk_files(source_base_dir, target_directory, args.vmname)
url = f"https://localhost:8006/api2/json/nodes/{args.pve_node}/qemu"
headers['Content-Type'] = "application/x-www-form-urlencoded"
response = requests.post(url, headers=headers, data=vm_config, verify=False)
print(f"Response Status: {response.status_code}")
print(f"Response Text: {response.text}")
if __name__ == "__main__":
main()