github.com/vmware/govmomi@v0.43.0/govc/vm/rdm/attach.go (about)

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