github.com/vmware/govmomi@v0.43.0/vmdk/disk_info.go (about)

     1  /*
     2  Copyright (c) 2024-2024 VMware, Inc. All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package vmdk
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  
    23  	"github.com/vmware/govmomi/object"
    24  	"github.com/vmware/govmomi/vim25"
    25  	"github.com/vmware/govmomi/vim25/mo"
    26  	"github.com/vmware/govmomi/vim25/types"
    27  )
    28  
    29  type VirtualDiskInfo struct {
    30  	CapacityInBytes int64
    31  	DeviceKey       int32
    32  	FileName        string
    33  	Size            int64
    34  	UniqueSize      int64
    35  }
    36  
    37  // GetVirtualDiskInfoByUUID returns information about a virtual disk identified
    38  // by the provided UUID. This method is valid for the following backing types:
    39  //
    40  // - VirtualDiskFlatVer2BackingInfo
    41  // - VirtualDiskSeSparseBackingInfo
    42  // - VirtualDiskRawDiskMappingVer1BackingInfo
    43  // - VirtualDiskSparseVer2BackingInfo
    44  // - VirtualDiskRawDiskVer2BackingInfo
    45  //
    46  // These are the only backing types that have a UUID property for comparing the
    47  // provided value.
    48  func GetVirtualDiskInfoByUUID(
    49  	ctx context.Context,
    50  	client *vim25.Client,
    51  	mo mo.VirtualMachine,
    52  	fetchProperties bool,
    53  	diskUUID string) (VirtualDiskInfo, error) {
    54  
    55  	if diskUUID == "" {
    56  		return VirtualDiskInfo{}, fmt.Errorf("diskUUID is empty")
    57  	}
    58  
    59  	switch {
    60  	case fetchProperties,
    61  		mo.Config == nil,
    62  		mo.Config.Hardware.Device == nil,
    63  		mo.LayoutEx == nil,
    64  		mo.LayoutEx.Disk == nil,
    65  		mo.LayoutEx.File == nil:
    66  
    67  		if ctx == nil {
    68  			return VirtualDiskInfo{}, fmt.Errorf("ctx is nil")
    69  		}
    70  		if client == nil {
    71  			return VirtualDiskInfo{}, fmt.Errorf("client is nil")
    72  		}
    73  
    74  		obj := object.NewVirtualMachine(client, mo.Self)
    75  
    76  		if err := obj.Properties(
    77  			ctx,
    78  			mo.Self,
    79  			[]string{"config", "layoutEx"},
    80  			&mo); err != nil {
    81  
    82  			return VirtualDiskInfo{},
    83  				fmt.Errorf("failed to retrieve properties: %w", err)
    84  		}
    85  	}
    86  
    87  	// Find the disk by UUID by inspecting all of the disk backing types that
    88  	// can have an associated UUID.
    89  	var (
    90  		disk     *types.VirtualDisk
    91  		fileName string
    92  	)
    93  	for i := range mo.Config.Hardware.Device {
    94  		switch tvd := mo.Config.Hardware.Device[i].(type) {
    95  		case *types.VirtualDisk:
    96  			switch tb := tvd.Backing.(type) {
    97  			case *types.VirtualDiskFlatVer2BackingInfo:
    98  				if tb.Uuid == diskUUID {
    99  					disk = tvd
   100  					fileName = tb.FileName
   101  				}
   102  			case *types.VirtualDiskSeSparseBackingInfo:
   103  				if tb.Uuid == diskUUID {
   104  					disk = tvd
   105  					fileName = tb.FileName
   106  				}
   107  			case *types.VirtualDiskRawDiskMappingVer1BackingInfo:
   108  				if tb.Uuid == diskUUID {
   109  					disk = tvd
   110  					fileName = tb.FileName
   111  				}
   112  			case *types.VirtualDiskSparseVer2BackingInfo:
   113  				if tb.Uuid == diskUUID {
   114  					disk = tvd
   115  					fileName = tb.FileName
   116  				}
   117  			case *types.VirtualDiskRawDiskVer2BackingInfo:
   118  				if tb.Uuid == diskUUID {
   119  					disk = tvd
   120  					fileName = tb.DescriptorFileName
   121  				}
   122  			}
   123  		}
   124  	}
   125  
   126  	if disk == nil {
   127  		return VirtualDiskInfo{},
   128  			fmt.Errorf("disk not found with uuid %q", diskUUID)
   129  	}
   130  
   131  	// Build a lookup table for determining if file key belongs to this disk
   132  	// chain.
   133  	diskFileKeys := map[int32]struct{}{}
   134  	for i := range mo.LayoutEx.Disk {
   135  		if d := mo.LayoutEx.Disk[i]; d.Key == disk.Key {
   136  			for j := range d.Chain {
   137  				for k := range d.Chain[j].FileKey {
   138  					diskFileKeys[d.Chain[j].FileKey[k]] = struct{}{}
   139  				}
   140  			}
   141  		}
   142  	}
   143  
   144  	// Sum the disk's total size and unique size.
   145  	var (
   146  		size       int64
   147  		uniqueSize int64
   148  	)
   149  	for i := range mo.LayoutEx.File {
   150  		f := mo.LayoutEx.File[i]
   151  		if _, ok := diskFileKeys[f.Key]; ok {
   152  			size += f.Size
   153  			uniqueSize += f.UniqueSize
   154  		}
   155  	}
   156  
   157  	return VirtualDiskInfo{
   158  		CapacityInBytes: disk.CapacityInBytes,
   159  		DeviceKey:       disk.Key,
   160  		FileName:        fileName,
   161  		Size:            size,
   162  		UniqueSize:      uniqueSize,
   163  	}, nil
   164  }