forked from hashicorp/terraform-provider-vsphere
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
New resource: vsphere_vmfs_datastore
This commit introduces the vsphere_vmfs_datastore resource, which can be used to manage VMFS-based datastores. Currently only whole disk support is included, however import functionality is planned so that one can import existing datastores that don't have full-disk extents, although whole disks will only be allowed to be added from there. Support for disk expansion may also be planned, depending on business case.
- Loading branch information
1 parent
1eac679
commit f5e8c1c
Showing
7 changed files
with
849 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package vsphere | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/vmware/govmomi" | ||
"github.com/vmware/govmomi/find" | ||
"github.com/vmware/govmomi/object" | ||
"github.com/vmware/govmomi/vim25/mo" | ||
"github.com/vmware/govmomi/vim25/types" | ||
) | ||
|
||
// datastoreFromID locates a Datastore by its managed object reference ID. | ||
func datastoreFromID(client *govmomi.Client, id string) (*object.Datastore, error) { | ||
finder := find.NewFinder(client.Client, false) | ||
|
||
ref := types.ManagedObjectReference{ | ||
Type: "Datastore", | ||
Value: id, | ||
} | ||
|
||
ctx, cancel := context.WithTimeout(context.Background(), defaultAPITimeout) | ||
defer cancel() | ||
ds, err := finder.ObjectReference(ctx, ref) | ||
if err != nil { | ||
return nil, fmt.Errorf("could not find datastore with id: %s: %s", id, err) | ||
} | ||
// Should be safe to return here. If our reference returned here and is not a | ||
// datastore, then we have bigger problems and to be honest we should be | ||
// panicking anyway. | ||
return ds.(*object.Datastore), nil | ||
} | ||
|
||
// datastoreProperties is a convenience method that wraps fetching the | ||
// Datastore MO from its higher-level object. | ||
func datastoreProperties(ds *object.Datastore) (*mo.Datastore, error) { | ||
ctx, cancel := context.WithTimeout(context.Background(), defaultAPITimeout) | ||
defer cancel() | ||
var props mo.Datastore | ||
if err := ds.Properties(ctx, ds.Reference(), nil, &props); err != nil { | ||
return nil, err | ||
} | ||
return &props, nil | ||
} | ||
|
||
// datastoreIsMissing checks if the error messages returned from | ||
// datastoreFromID indicates that the datastore is missing. This is used in | ||
// various deletion checks. | ||
func datastoreIsMissing(id string, err error) bool { | ||
msg := fmt.Sprintf("could not find datastore with id: %s: ServerFaultCode: The object 'vim.Datastore:%s' has already been deleted or has not been completely created", id, id) | ||
|
||
if err.Error() == msg { | ||
return true | ||
} | ||
return false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package vsphere | ||
|
||
import ( | ||
"github.com/hashicorp/terraform/helper/schema" | ||
"github.com/vmware/govmomi/vim25/types" | ||
) | ||
|
||
// schemaDatastoreSummary returns schema items for resources that | ||
// need to work with a DatastoreSummary. | ||
func schemaDatastoreSummary() map[string]*schema.Schema { | ||
return map[string]*schema.Schema{ | ||
// Note that the following fields are not represented in the schema here: | ||
// * Name (more than likely the ID attribute and will be represented in | ||
// resource schema) | ||
// * Type (redundant attribute as the datastore type will be represented by | ||
// the resource) | ||
"accessible": &schema.Schema{ | ||
Type: schema.TypeBool, | ||
Description: "The connectivity status of the datastore. If this is false, some other computed attributes may be out of date.", | ||
Computed: true, | ||
}, | ||
"capacity": &schema.Schema{ | ||
Type: schema.TypeInt, | ||
Description: "Maximum capacity of the datastore, in bytes.", | ||
Computed: true, | ||
}, | ||
"free_space": &schema.Schema{ | ||
Type: schema.TypeInt, | ||
Description: "Available space of this datastore, in bytes.", | ||
Computed: true, | ||
}, | ||
"maintenance_mode": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Description: "The current maintenance mode state of the datastore.", | ||
Computed: true, | ||
}, | ||
"multiple_host_access": &schema.Schema{ | ||
Type: schema.TypeBool, | ||
Description: "If true, more than one host in the datacenter has been configured with access to the datastore", | ||
Computed: true, | ||
}, | ||
"uncommitted_space": &schema.Schema{ | ||
Type: schema.TypeInt, | ||
Description: "Total additional storage space, in bytes, potentially used by all virtual machines on this datastore.", | ||
Computed: true, | ||
}, | ||
"url": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Description: "The unique locator for the datastore.", | ||
Computed: true, | ||
}, | ||
} | ||
} | ||
|
||
// flattenDatastoreSummary reads various fields from a DatastoreSummary into | ||
// the passed in ResourceData. | ||
func flattenDatastoreSummary(d *schema.ResourceData, obj *types.DatastoreSummary) error { | ||
d.Set("accessible", obj.Accessible) | ||
d.Set("capacity", obj.Capacity) | ||
d.Set("free_space", obj.FreeSpace) | ||
d.Set("maintenance_mode", obj.MaintenanceMode) | ||
d.Set("multiple_host_access", obj.MultipleHostAccess) | ||
d.Set("uncommitted_space", obj.Uncommitted) | ||
d.Set("url", obj.Url) | ||
|
||
// Set the name attribute off of the name here - since we do not track this | ||
// here we check for errors | ||
if err := d.Set("name", obj.Name); err != nil { | ||
return err | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
package vsphere | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/vmware/govmomi" | ||
"github.com/vmware/govmomi/object" | ||
"github.com/vmware/govmomi/vim25/methods" | ||
"github.com/vmware/govmomi/vim25/types" | ||
) | ||
|
||
// hostDatastoreSystemFromHostSystemID locates a HostDatastoreSystem from a | ||
// specified HostSystem managed object ID. | ||
func hostDatastoreSystemFromHostSystemID(client *govmomi.Client, hsID string) (*object.HostDatastoreSystem, error) { | ||
hs, err := hostSystemFromID(client, hsID) | ||
if err != nil { | ||
return nil, err | ||
} | ||
ctx, cancel := context.WithTimeout(context.Background(), defaultAPITimeout) | ||
defer cancel() | ||
return hs.ConfigManager().DatastoreSystem(ctx) | ||
} | ||
|
||
// availableScsiDisk checks to make sure that a disk is available for use in a | ||
// VMFS datastore, and returns the ScsiDisk. | ||
func availableScsiDisk(dss *object.HostDatastoreSystem, name string) (*types.HostScsiDisk, error) { | ||
ctx, cancel := context.WithTimeout(context.Background(), defaultAPITimeout) | ||
defer cancel() | ||
disks, err := dss.QueryAvailableDisksForVmfs(ctx) | ||
if err != nil { | ||
return nil, fmt.Errorf("cannot query available disks: %s", err) | ||
} | ||
|
||
var disk *types.HostScsiDisk | ||
for _, d := range disks { | ||
if d.CanonicalName == name { | ||
disk = &d | ||
break | ||
} | ||
} | ||
if disk == nil { | ||
return nil, fmt.Errorf("%s does not seem to be a disk available for VMFS", name) | ||
} | ||
return disk, nil | ||
} | ||
|
||
// diskSpecForCreate checks to make sure that a disk is available to be used to | ||
// create a VMFS datastore, specifically in its entirety, and returns a | ||
// respective VmfsDatastoreCreateSpec. | ||
func diskSpecForCreate(dss *object.HostDatastoreSystem, name string) (*types.VmfsDatastoreCreateSpec, error) { | ||
disk, err := availableScsiDisk(dss, name) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
ctx, cancel := context.WithTimeout(context.Background(), defaultAPITimeout) | ||
defer cancel() | ||
options, err := dss.QueryVmfsDatastoreCreateOptions(ctx, disk.DevicePath) | ||
if err != nil { | ||
return nil, fmt.Errorf("could not get disk creation options for %s: %s", name, err) | ||
} | ||
var option *types.VmfsDatastoreOption | ||
for _, o := range options { | ||
if _, ok := o.Info.(*types.VmfsDatastoreAllExtentOption); ok { | ||
option = &o | ||
break | ||
} | ||
} | ||
if option == nil { | ||
return nil, fmt.Errorf("cannot use entire disk on device %s for datastore", name) | ||
} | ||
return option.Spec.(*types.VmfsDatastoreCreateSpec), nil | ||
} | ||
|
||
// diskSpecForExtend checks to make sure that a disk is available to be | ||
// used to extend a VMFS datastore, specifically in its entirety, and returns a | ||
// respective VmfsDatastoreExtendSpec if it is. An error is returned if it's | ||
// not. | ||
func diskSpecForExtend(dss *object.HostDatastoreSystem, ds *object.Datastore, name string) (*types.VmfsDatastoreExtendSpec, error) { | ||
disk, err := availableScsiDisk(dss, name) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
ctx, cancel := context.WithTimeout(context.Background(), defaultAPITimeout) | ||
defer cancel() | ||
options, err := queryVmfsDatastoreExtendOptions(ctx, dss, ds, disk.DevicePath, true) | ||
if err != nil { | ||
return nil, fmt.Errorf("could not get disk extension options for %s: %s", name, err) | ||
} | ||
var option *types.VmfsDatastoreOption | ||
for _, o := range options { | ||
if _, ok := o.Info.(*types.VmfsDatastoreAllExtentOption); ok { | ||
option = &o | ||
break | ||
} | ||
} | ||
if option == nil { | ||
return nil, fmt.Errorf("cannot use entire disk on device %s for datastore", name) | ||
} | ||
return option.Spec.(*types.VmfsDatastoreExtendSpec), nil | ||
} | ||
|
||
// removeDatastore is a convenience method for removing a referenced datastore. | ||
func removeDatastore(s *object.HostDatastoreSystem, ds *object.Datastore) error { | ||
ctx, cancel := context.WithTimeout(context.Background(), defaultAPITimeout) | ||
defer cancel() | ||
return s.Remove(ctx, ds) | ||
} | ||
|
||
// queryVmfsDatastoreExtendOptions is a stop-gap method that implements | ||
// QueryVmfsDatastoreExtendOptions. It will be removed once the higher level | ||
// HostDatastoreSystem object supports this method. | ||
func queryVmfsDatastoreExtendOptions(ctx context.Context, s *object.HostDatastoreSystem, ds *object.Datastore, devicePath string, suppressExpandCandidates bool) ([]types.VmfsDatastoreOption, error) { | ||
req := types.QueryVmfsDatastoreExtendOptions{ | ||
This: s.Reference(), | ||
Datastore: ds.Reference(), | ||
DevicePath: devicePath, | ||
SuppressExpandCandidates: &suppressExpandCandidates, | ||
} | ||
|
||
res, err := methods.QueryVmfsDatastoreExtendOptions(ctx, s.Client(), &req) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return res.Returnval, nil | ||
} | ||
|
||
// extendVmfsDatastore is a stop-gap method that implements | ||
// ExtendVmfsDatastore. It will be removed once the higher level | ||
// HostDatastoreSystem object supports this method. | ||
func extendVmfsDatastore(ctx context.Context, s *object.HostDatastoreSystem, ds *object.Datastore, spec types.VmfsDatastoreExtendSpec) (*object.Datastore, error) { | ||
req := types.ExtendVmfsDatastore{ | ||
This: s.Reference(), | ||
Datastore: ds.Reference(), | ||
Spec: spec, | ||
} | ||
|
||
res, err := methods.ExtendVmfsDatastore(ctx, s.Client(), &req) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return object.NewDatastore(s.Client(), res.Returnval), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.