github.com/vmware/govmomi@v0.37.1/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 }