From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id 6EECE1FF17A for ; Fri, 18 Jul 2025 18:18:35 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 358E535175; Fri, 18 Jul 2025 18:19:40 +0200 (CEST) From: "Max R. Carrara" To: pve-devel@lists.proxmox.com Date: Fri, 18 Jul 2025 18:19:01 +0200 Message-Id: <20250718161905.461482-2-m.carrara@proxmox.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20250718161905.461482-1-m.carrara@proxmox.com> References: <20250718161905.461482-1-m.carrara@proxmox.com> MIME-Version: 1.0 X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1752855544025 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.082 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: [pve-devel] [PATCH v1 pve-esxi-import-tools 1/5] listvms: respect new type hints of pyVmomi package X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Proxmox VE development discussion Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pve-devel-bounces@lists.proxmox.com Sender: "pve-devel" This makes mypy on trixie happy again. Make the type hints explicit; even though this is a little more verbose, it should make any typing-related changes more visible in the future. Also return (hopefully) sane defaults wherever possible. Note that Python doesn't have something like "null-aware member access" like JS does, so there isn't really any prettier version of doing this. (Besides, I have *never* seen as many `Optional`s in any Python codebase as in the pyVmomi package's type stubs, let alone their "on-demand loading" of types.) Signed-off-by: Max R. Carrara --- listvms.py | 95 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 81 insertions(+), 14 deletions(-) diff --git a/listvms.py b/listvms.py index 44f207c..221d562 100755 --- a/listvms.py +++ b/listvms.py @@ -162,14 +162,29 @@ def get_datacenter_of_vm(vm: vim.VirtualMachine) -> vim.Datacenter | None: def list_vms(service_instance: vim.ServiceInstance) -> list[vim.VirtualMachine]: """List all VMs on the ESXi/vCenter server.""" - content = service_instance.content - vm_view: Any = content.viewManager.CreateContainerView( + + content: vim.ServiceInstanceContent | None = service_instance.content + + if content is None: + return [] + + view_manager: vim.view.ViewManager | None = content.viewManager + + if view_manager is None: + return [] + + vm_view = view_manager.CreateContainerView( content.rootFolder, [vim.VirtualMachine], True, ) + + if vm_view is None: + return [] + vms = vm_view.view vm_view.Destroy() + return vms @@ -180,23 +195,42 @@ def parse_file_path(path) -> tuple[str, str]: return (datastore_name, relative_path) -def get_vm_vmx_info(vm: vim.VirtualMachine) -> VmVmxInfo: +def get_vm_vmx_info(vm: vim.VirtualMachine) -> VmVmxInfo | None: """Extract VMX file path and checksum from a VM object.""" - datastore_name, relative_vmx_path = parse_file_path( - vm.config.files.vmPathName + + config: vim.vm.ConfigInfo | None = vm.config + + if config is None: + return None + + files: vim.vm.FileInfo | None = config.files + + if files is None: + return None + + vm_path_name: str | None = files.vmPathName + + if vm_path_name is None: + return None + + datastore_name, relative_vmx_path = parse_file_path(vm_path_name) + checksum = ( + config.vmxConfigChecksum.hex() if config.vmxConfigChecksum else "N/A" ) return VmVmxInfo( datastore=datastore_name, path=relative_vmx_path, - checksum=vm.config.vmxConfigChecksum.hex() - if vm.config.vmxConfigChecksum - else "N/A", + checksum=checksum, ) def get_vm_disk_info(vm: vim.VirtualMachine) -> list[VmDiskInfo]: - disks = [] + disks: list[VmDiskInfo] = [] + + if vm.config is None: + return disks + for device in vm.config.hardware.device: if isinstance(device, vim.vm.device.VirtualDisk): try: @@ -217,12 +251,27 @@ def get_all_datacenters( service_instance: vim.ServiceInstance, ) -> list[vim.Datacenter]: """Retrieve all datacenters from the ESXi/vCenter server.""" - content = service_instance.content - dc_view: Any = content.viewManager.CreateContainerView( + + content: vim.ServiceInstanceContent | None = service_instance.content + + if content is None: + return [] + + view_manager: vim.view.ViewManager | None = content.viewManager + + if view_manager is None: + return [] + + dc_view = view_manager.CreateContainerView( content.rootFolder, [vim.Datacenter], True ) + + if dc_view is None: + return [] + datacenters = dc_view.view dc_view.Destroy() + return datacenters @@ -242,13 +291,28 @@ def fetch_and_update_vm_data(vm: vim.VirtualMachine, data: dict[Any, Any]): vms = data[datacenter.name].setdefault("vms", {}) datastores = data[datacenter.name].setdefault("datastores", {}) + config: vim.vm.ConfigInfo | None = vm.config + + if config is None: + return + + vm_vmx_info: VmVmxInfo | None = get_vm_vmx_info(vm) + + if vm_vmx_info is None: + return + + runtime: vim.vm.RuntimeInfo | None = vm.runtime + + if runtime is None: + return + vms[vm.name] = VmInfo( - config=get_vm_vmx_info(vm), + config=vm_vmx_info, disks=get_vm_disk_info(vm), - power=str(vm.runtime.powerState), + power=str(runtime.powerState), ) - datastores.update({ds.name: ds.url for ds in vm.config.datastoreUrl}) + datastores.update({ds.name: ds.url for ds in config.datastoreUrl}) def is_vcls_agent_vm(vm: vim.VirtualMachine) -> bool: @@ -261,6 +325,9 @@ def is_vcls_agent_vm(vm: vim.VirtualMachine) -> bool: for cfg in vm.config.extraConfig) def is_diskless_vm(vm: vim.VirtualMachine) -> bool: + if vm.config is None or vm.config.files is None: + return True + datastore_name, _ = parse_file_path(vm.config.files.vmPathName) return not datastore_name -- 2.39.5 _______________________________________________ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel