github.com/vmware/govmomi@v0.51.0/cli/vm/rdm/attach.go (about) 1 // © Broadcom. All Rights Reserved. 2 // The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 3 // SPDX-License-Identifier: Apache-2.0 4 5 package rdm 6 7 import ( 8 "context" 9 "flag" 10 "fmt" 11 "strings" 12 13 "github.com/vmware/govmomi/cli" 14 "github.com/vmware/govmomi/cli/flags" 15 "github.com/vmware/govmomi/vim25/types" 16 ) 17 18 type attach struct { 19 *flags.VirtualMachineFlag 20 21 device string 22 } 23 24 func init() { 25 cli.Register("vm.rdm.attach", &attach{}) 26 } 27 28 func (cmd *attach) Register(ctx context.Context, f *flag.FlagSet) { 29 30 cmd.VirtualMachineFlag, ctx = flags.NewVirtualMachineFlag(ctx) 31 cmd.VirtualMachineFlag.Register(ctx, f) 32 33 f.StringVar(&cmd.device, "device", "", "Device Name") 34 } 35 36 func (cmd *attach) Description() string { 37 return `Attach DEVICE to VM with RDM. 38 39 Examples: 40 govc vm.rdm.attach -vm VM -device /vmfs/devices/disks/naa.000000000000000000000000000000000` 41 } 42 43 func (cmd *attach) Process(ctx context.Context) error { 44 if err := cmd.VirtualMachineFlag.Process(ctx); err != nil { 45 return err 46 } 47 return nil 48 } 49 50 // This piece of code was developed mainly thanks to the project govmax on github.com 51 // This file in particular https://github.com/codedellemc/govmax/blob/master/api/v1/vmomi.go 52 func (cmd *attach) Run(ctx context.Context, f *flag.FlagSet) error { 53 vm, err := cmd.VirtualMachine() 54 if err != nil { 55 return err 56 } 57 58 if vm == nil { 59 return flag.ErrHelp 60 } 61 62 devices, err := vm.Device(ctx) 63 if err != nil { 64 return err 65 } 66 67 controller, err := devices.FindSCSIController("") 68 if err != nil { 69 return err 70 } 71 72 vmConfigOptions, err := queryConfigTarget(ctx, vm) 73 if err != nil { 74 return err 75 } 76 77 for _, scsiDisk := range vmConfigOptions.ScsiDisk { 78 if !strings.Contains(scsiDisk.Disk.CanonicalName, cmd.device) { 79 continue 80 } 81 var backing types.VirtualDiskRawDiskMappingVer1BackingInfo 82 backing.CompatibilityMode = string(types.VirtualDiskCompatibilityModePhysicalMode) 83 backing.DeviceName = scsiDisk.Disk.DeviceName 84 for _, descriptor := range scsiDisk.Disk.Descriptor { 85 if strings.HasPrefix(descriptor.Id, "vml.") { 86 backing.LunUuid = descriptor.Id 87 break 88 } 89 } 90 var device types.VirtualDisk 91 device.Backing = &backing 92 device.ControllerKey = controller.VirtualController.Key 93 94 var unitNumber *int32 95 scsiCtrlUnitNumber := controller.VirtualController.UnitNumber 96 var u int32 97 for u = 0; u < 16; u++ { 98 free := true 99 for _, d := range devices { 100 if d.GetVirtualDevice().ControllerKey == device.GetVirtualDevice().ControllerKey { 101 if u == *(d.GetVirtualDevice().UnitNumber) || u == *scsiCtrlUnitNumber { 102 free = false 103 } 104 } 105 } 106 if free && u != 7 { 107 unitNumber = &u 108 break 109 } 110 } 111 device.UnitNumber = unitNumber 112 113 spec := types.VirtualMachineConfigSpec{} 114 115 config := &types.VirtualDeviceConfigSpec{ 116 Device: &device, 117 Operation: types.VirtualDeviceConfigSpecOperationAdd, 118 } 119 120 config.FileOperation = types.VirtualDeviceConfigSpecFileOperationCreate 121 122 spec.DeviceChange = append(spec.DeviceChange, config) 123 124 task, err := vm.Reconfigure(ctx, spec) 125 if err != nil { 126 return err 127 } 128 129 err = task.Wait(ctx) 130 if err != nil { 131 return fmt.Errorf("error adding device %+v \n with backing %+v \nLogged Item: %s", device, backing, err) 132 } 133 return nil 134 135 } 136 return fmt.Errorf("error: No LUN with device name containing %s found", cmd.device) 137 }