github.com/vmware/govmomi@v0.37.2/govc/datastore/create.go (about)

     1  /*
     2  Copyright (c) 2015-2016 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 datastore
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"flag"
    23  	"fmt"
    24  	"os"
    25  	"path/filepath"
    26  	"strings"
    27  
    28  	"github.com/vmware/govmomi/govc/cli"
    29  	"github.com/vmware/govmomi/govc/flags"
    30  	"github.com/vmware/govmomi/object"
    31  	"github.com/vmware/govmomi/vim25/soap"
    32  	"github.com/vmware/govmomi/vim25/types"
    33  )
    34  
    35  type create struct {
    36  	*flags.HostSystemFlag
    37  
    38  	// Generic options
    39  	Type  typeFlag
    40  	Name  string
    41  	Force bool
    42  
    43  	// Options for NAS
    44  	RemoteHost string
    45  	RemotePath string
    46  	AccessMode string
    47  	UserName   string
    48  	Password   string
    49  
    50  	// Options for VMFS
    51  	DiskCanonicalName string
    52  	Version           *int32
    53  
    54  	// Options for local
    55  	Path string
    56  }
    57  
    58  func init() {
    59  	cli.Register("datastore.create", &create{})
    60  }
    61  
    62  var nasTypes = []string{
    63  	string(types.HostFileSystemVolumeFileSystemTypeNFS),
    64  	string(types.HostFileSystemVolumeFileSystemTypeNFS41),
    65  	string(types.HostFileSystemVolumeFileSystemTypeCIFS),
    66  }
    67  
    68  var vmfsTypes = []string{
    69  	string(types.HostFileSystemVolumeFileSystemTypeVMFS),
    70  }
    71  
    72  var localTypes = []string{
    73  	"local",
    74  }
    75  
    76  var allTypes = []string{}
    77  
    78  func init() {
    79  	allTypes = append(allTypes, nasTypes...)
    80  	allTypes = append(allTypes, vmfsTypes...)
    81  	allTypes = append(allTypes, localTypes...)
    82  }
    83  
    84  type typeFlag string
    85  
    86  func (t *typeFlag) Set(s string) error {
    87  	s = strings.ToLower(s)
    88  	for _, e := range allTypes {
    89  		if s == strings.ToLower(e) {
    90  			*t = typeFlag(e)
    91  			return nil
    92  		}
    93  	}
    94  
    95  	return fmt.Errorf("unknown type")
    96  }
    97  
    98  func (t *typeFlag) String() string {
    99  	return string(*t)
   100  }
   101  
   102  func (t *typeFlag) partOf(m []string) bool {
   103  	for _, e := range m {
   104  		if t.String() == e {
   105  			return true
   106  		}
   107  	}
   108  	return false
   109  }
   110  
   111  func (t *typeFlag) IsNasType() bool {
   112  	return t.partOf(nasTypes)
   113  }
   114  
   115  func (t *typeFlag) IsVmfsType() bool {
   116  	return t.partOf(vmfsTypes)
   117  }
   118  
   119  func (t *typeFlag) IsLocalType() bool {
   120  	return t.partOf(localTypes)
   121  }
   122  
   123  func (cmd *create) Register(ctx context.Context, f *flag.FlagSet) {
   124  	cmd.HostSystemFlag, ctx = flags.NewHostSystemFlag(ctx)
   125  	cmd.HostSystemFlag.Register(ctx, f)
   126  
   127  	modes := []string{
   128  		string(types.HostMountModeReadOnly),
   129  		string(types.HostMountModeReadWrite),
   130  	}
   131  
   132  	f.StringVar(&cmd.Name, "name", "", "Datastore name")
   133  	f.Var(&cmd.Type, "type", fmt.Sprintf("Datastore type (%s)", strings.Join(allTypes, "|")))
   134  	f.BoolVar(&cmd.Force, "force", false, "Ignore DuplicateName error if datastore is already mounted on a host")
   135  
   136  	// Options for NAS
   137  	f.StringVar(&cmd.RemoteHost, "remote-host", "", "Remote hostname of the NAS datastore")
   138  	f.StringVar(&cmd.RemotePath, "remote-path", "", "Remote path of the NFS mount point")
   139  	f.StringVar(&cmd.AccessMode, "mode", modes[0],
   140  		fmt.Sprintf("Access mode for the mount point (%s)", strings.Join(modes, "|")))
   141  	f.StringVar(&cmd.UserName, "username", "", "Username to use when connecting (CIFS only)")
   142  	f.StringVar(&cmd.Password, "password", "", "Password to use when connecting (CIFS only)")
   143  
   144  	// Options for VMFS
   145  	f.StringVar(&cmd.DiskCanonicalName, "disk", "", "Canonical name of disk (VMFS only)")
   146  	f.Var(flags.NewOptionalInt32(&cmd.Version), "version", "VMFS major version")
   147  
   148  	// Options for Local
   149  	f.StringVar(&cmd.Path, "path", "", "Local directory path for the datastore (local only)")
   150  }
   151  
   152  func (cmd *create) Process(ctx context.Context) error {
   153  	if err := cmd.HostSystemFlag.Process(ctx); err != nil {
   154  		return err
   155  	}
   156  	return nil
   157  }
   158  
   159  func (cmd *create) Usage() string {
   160  	return "HOST..."
   161  }
   162  
   163  func (cmd *create) Description() string {
   164  	return `Create datastore on HOST.
   165  
   166  Examples:
   167    govc datastore.create -type nfs -name nfsDatastore -remote-host 10.143.2.232 -remote-path /share cluster1
   168    govc datastore.create -type vmfs -name vmfsDatastore -disk=mpx.vmhba0:C0:T0:L0 cluster1
   169    govc datastore.create -type local -name localDatastore -path /var/datastore host1`
   170  }
   171  
   172  func (cmd *create) Run(ctx context.Context, f *flag.FlagSet) error {
   173  	hosts, err := cmd.HostSystems(f.Args())
   174  	if err != nil {
   175  		return err
   176  	}
   177  
   178  	switch {
   179  	case cmd.Type.IsNasType():
   180  		return cmd.CreateNasDatastore(ctx, hosts)
   181  	case cmd.Type.IsVmfsType():
   182  		return cmd.CreateVmfsDatastore(ctx, hosts)
   183  	case cmd.Type.IsLocalType():
   184  		return cmd.CreateLocalDatastore(ctx, hosts)
   185  	default:
   186  		return fmt.Errorf("unhandled type %#v", cmd.Type)
   187  	}
   188  }
   189  
   190  func (cmd *create) GetHostNasVolumeSpec() types.HostNasVolumeSpec {
   191  	localPath := cmd.Path
   192  	if localPath == "" {
   193  		localPath = cmd.Name
   194  	}
   195  
   196  	s := types.HostNasVolumeSpec{
   197  		LocalPath:  localPath,
   198  		Type:       cmd.Type.String(),
   199  		RemoteHost: cmd.RemoteHost,
   200  		RemotePath: cmd.RemotePath,
   201  		AccessMode: cmd.AccessMode,
   202  		UserName:   cmd.UserName,
   203  		Password:   cmd.Password,
   204  	}
   205  
   206  	return s
   207  }
   208  
   209  func (cmd *create) CreateNasDatastore(ctx context.Context, hosts []*object.HostSystem) error {
   210  	object := types.ManagedObjectReference{
   211  		Type:  "Datastore",
   212  		Value: fmt.Sprintf("%s:%s", cmd.RemoteHost, cmd.RemotePath),
   213  	}
   214  
   215  	spec := cmd.GetHostNasVolumeSpec()
   216  
   217  	for _, host := range hosts {
   218  		ds, err := host.ConfigManager().DatastoreSystem(ctx)
   219  		if err != nil {
   220  			return err
   221  		}
   222  
   223  		_, err = ds.CreateNasDatastore(ctx, spec)
   224  		if err != nil {
   225  			if soap.IsSoapFault(err) {
   226  				switch fault := soap.ToSoapFault(err).VimFault().(type) {
   227  				case types.PlatformConfigFault:
   228  					if len(fault.FaultMessage) != 0 {
   229  						return errors.New(fault.FaultMessage[0].Message)
   230  					}
   231  				case types.DuplicateName:
   232  					if cmd.Force && fault.Object == object {
   233  						fmt.Fprintf(os.Stderr, "%s: '%s' already mounted\n",
   234  							host.InventoryPath, cmd.Name)
   235  						continue
   236  					}
   237  				}
   238  			}
   239  
   240  			return fmt.Errorf("%s: %s", host.InventoryPath, err)
   241  		}
   242  	}
   243  
   244  	return nil
   245  }
   246  
   247  func (cmd *create) CreateVmfsDatastore(ctx context.Context, hosts []*object.HostSystem) error {
   248  	for _, host := range hosts {
   249  		ds, err := host.ConfigManager().DatastoreSystem(ctx)
   250  		if err != nil {
   251  			return err
   252  		}
   253  
   254  		// Find the specified disk
   255  		disks, err := ds.QueryAvailableDisksForVmfs(ctx)
   256  		if err != nil {
   257  			return err
   258  		}
   259  
   260  		var disk *types.HostScsiDisk
   261  		for _, e := range disks {
   262  			if e.CanonicalName == cmd.DiskCanonicalName {
   263  				disk = &e
   264  				break
   265  			}
   266  		}
   267  
   268  		if disk == nil {
   269  			return fmt.Errorf("no eligible disk found for name %#v", cmd.DiskCanonicalName)
   270  		}
   271  
   272  		// Query for creation options and pick the right one
   273  		options, err := ds.QueryVmfsDatastoreCreateOptions(ctx, disk.DevicePath)
   274  		if err != nil {
   275  			return err
   276  		}
   277  
   278  		var option *types.VmfsDatastoreOption
   279  		for _, e := range options {
   280  			if _, ok := e.Info.(*types.VmfsDatastoreAllExtentOption); ok {
   281  				option = &e
   282  				break
   283  			}
   284  		}
   285  
   286  		if option == nil {
   287  			return fmt.Errorf("cannot use entire disk for datastore for name %#v", cmd.DiskCanonicalName)
   288  		}
   289  
   290  		spec := *option.Spec.(*types.VmfsDatastoreCreateSpec)
   291  		spec.Vmfs.VolumeName = cmd.Name
   292  		if cmd.Version != nil {
   293  			spec.Vmfs.MajorVersion = *cmd.Version
   294  		}
   295  		_, err = ds.CreateVmfsDatastore(ctx, spec)
   296  		if err != nil {
   297  			return err
   298  		}
   299  	}
   300  
   301  	return nil
   302  }
   303  
   304  func (cmd *create) CreateLocalDatastore(ctx context.Context, hosts []*object.HostSystem) error {
   305  	for _, host := range hosts {
   306  		ds, err := host.ConfigManager().DatastoreSystem(ctx)
   307  		if err != nil {
   308  			return err
   309  		}
   310  
   311  		if cmd.Path == "" {
   312  			cmd.Path = cmd.Name
   313  		}
   314  
   315  		if cmd.Name == "" {
   316  			cmd.Name = filepath.Base(cmd.Path)
   317  		}
   318  
   319  		_, err = ds.CreateLocalDatastore(ctx, cmd.Name, cmd.Path)
   320  		if err != nil {
   321  			return err
   322  		}
   323  	}
   324  
   325  	return nil
   326  }