Skip to content

Commit

Permalink
Merge pull request #881 from terraform-providers/mnshtiwari:f-spbm-su…
Browse files Browse the repository at this point in the history
…pport

Pulling in additional acceptance tests and doc updates
  • Loading branch information
bill-rich committed Jan 24, 2020
2 parents 05cd12c + 3222100 commit bc1eb53
Show file tree
Hide file tree
Showing 12 changed files with 477 additions and 51 deletions.
99 changes: 50 additions & 49 deletions tf-vsphere-devrc.mk.example
Original file line number Diff line number Diff line change
Expand Up @@ -21,55 +21,56 @@ export VSPHERE_ALLOW_UNVERIFIED_SSL ?= false

# The following variables are shared across various tests. To ensure all tests
# succeed, it's probably best to set all of these to valid values.
export VSPHERE_TEMPLATE ?= base-linux # VM template to clone
export VSPHERE_TEMPLATE_WINDOWS ?= base-win # Windows VM template
export VSPHERE_TEMPLATE_COREOS ?= base-core # CoreOS template from OVA
export VSPHERE_TEMPLATE_ISO_TRANSPORT ?= base-vappt # Template with vApp ISO transport
export VSPHERE_NETWORK_LABEL ?= vm-network # Port group label
export VSPHERE_NETWORK_LABEL_DHCP ?= vm-network # Port group label for DHCP
export VSPHERE_NETWORK_LABEL_PXE ?= vm-network # Port group label for PXE
export VSPHERE_IPV4_ADDRESS ?= 10.0.0.100 # Customization IP address
export VSPHERE_IPV4_PREFIX ?= 24 # Customization netmask
export VSPHERE_IPV4_GATEWAY ?= 10.0.0.1 # Customization gateway
export VSPHERE_DNS ?= 10.0.0.10 # Customization DNS
export VSPHERE_DATACENTER ?= vm-dc # VM placement DC
export VSPHERE_CLUSTER ?= vm-clus1 # VM placement cluster
export VSPHERE_CLUSTER2 ?= vm-clus2 # Extra cluster for testing
export VSPHERE_EMPTY_CLUSTER ?= clus-empty # Empty cluster for testing
export VSPHERE_RESOURCE_POOL ?= vm-respool # VM resource resource pool
export VSPHERE_DATASTORE ?= datastore1 # VM placement datastore
export VSPHERE_DATASTORE2 ?= datastore2 # 2nd datastore for vMotion
export VSPHERE_INIT_TYPE ?= thin # vDisk type
export VSPHERE_ADAPTER_TYPE ?= lsiLogic # Virtual disk adapter type
export VSPHERE_LICENSE ?= key # License resource test key
export VSPHERE_DC_FOLDER ?= dc-folder # DC resource test folder
export VSPHERE_ESXI_HOST ?= esxi1 # ESXi host to work with
export VSPHERE_ESXI_HOST2 ?= esxi2 # 2nd ESXi host to work with
export VSPHERE_ESXI_HOST3 ?= esxi3 # 3nd ESXi host to work with
export VSPHERE_ESXI_HOST4 ?= esxi4 # 4th ESXi host to work with
export VSPHERE_ESXI_HOST5 ?= esxi5 # 5th ESXi host to work with
export VSPHERE_ESXI_HOST6 ?= esxi6 # 6th ESXi host to work with
export VSPHERE_ESXI_HOST7 ?= esxi7 # 7th ESXi host to work with
export VSPHERE_HOST_NIC0 ?= vmnic0 # NIC0 for host net tests
export VSPHERE_HOST_NIC1 ?= vmnic1 # NIC1 for host net tests
export VSPHERE_VMFS_EXPECTED ?= scsi-name # Name of expected SCSI disk
export VSPHERE_VMFS_REGEXP ?= expr # Regexp for SCSI disk search
export VSPHERE_DS_VMFS_DISK0 ?= scsi-name0 # 1st disk for vmfs_datastore
export VSPHERE_DS_VMFS_DISK1 ?= scsi-name1 # 2nd disk for vmfs_datastore
export VSPHERE_DS_VMFS_DISK2 ?= scsi-name2 # 3rd disk for vmfs_datastore
export VSPHERE_DS_FOLDER ?= ds-folder # Path to a datastore folder
export VSPHERE_NAS_HOST ?= nas-host # Hostname for nas_datastore
export VSPHERE_NFS_PATH ?= nfs-path # NFS path for nas_datastore
export VSPHERE_NFS_PATH2 ?= nfs-path # 2nd nas_datastore path
export VSPHERE_FOLDER_V0_PATH ?= old-folder # vsphere_folder state test
export VSPHERE_ISO_FILE ?= iso-file # ISO file for CDROM device
export VSPHERE_ISO_DATASTORE ?= iso-ds # ISO file for CDROM device
export VSPHERE_VM_V1_PATH ?= vm-path # VM resource state migration
export VSPHERE_VAPP_CONTAINER ?= vapp-path # Path to a vApp container
export VSPHERE_PERSIST_SESSION ?= true # Session persistence
export VSPHERE_REST_SESSION_PATH ?= rest-path # Path to store rest sessions
export VSPHERE_VIM_SESSION_PATH ?= vim-path # Path to store vim sessions
export VSPHERE_TEMPLATE ?= base-linux # VM template to clone
export VSPHERE_TEMPLATE_WINDOWS ?= base-win # Windows VM template
export VSPHERE_TEMPLATE_COREOS ?= base-core # CoreOS template from OVA
export VSPHERE_TEMPLATE_ISO_TRANSPORT ?= base-vappt # Template with vApp ISO transport
export VSPHERE_NETWORK_LABEL ?= vm-network # Port group label
export VSPHERE_NETWORK_LABEL_DHCP ?= vm-network # Port group label for DHCP
export VSPHERE_NETWORK_LABEL_PXE ?= vm-network # Port group label for PXE
export VSPHERE_IPV4_ADDRESS ?= 10.0.0.100 # Customization IP address
export VSPHERE_IPV4_PREFIX ?= 24 # Customization netmask
export VSPHERE_IPV4_GATEWAY ?= 10.0.0.1 # Customization gateway
export VSPHERE_DNS ?= 10.0.0.10 # Customization DNS
export VSPHERE_DATACENTER ?= vm-dc # VM placement DC
export VSPHERE_CLUSTER ?= vm-clus1 # VM placement cluster
export VSPHERE_CLUSTER2 ?= vm-clus2 # Extra cluster for testing
export VSPHERE_EMPTY_CLUSTER ?= clus-empty # Empty cluster for testing
export VSPHERE_RESOURCE_POOL ?= vm-respool # VM resource resource pool
export VSPHERE_DATASTORE ?= datastore1 # VM placement datastore
export VSPHERE_DATASTORE2 ?= datastore2 # 2nd datastore for vMotion
export VSPHERE_INIT_TYPE ?= thin # vDisk type
export VSPHERE_ADAPTER_TYPE ?= lsiLogic # Virtual disk adapter type
export VSPHERE_LICENSE ?= key # License resource test key
export VSPHERE_DC_FOLDER ?= dc-folder # DC resource test folder
export VSPHERE_ESXI_HOST ?= esxi1 # ESXi host to work with
export VSPHERE_ESXI_HOST2 ?= esxi2 # 2nd ESXi host to work with
export VSPHERE_ESXI_HOST3 ?= esxi3 # 3nd ESXi host to work with
export VSPHERE_ESXI_HOST4 ?= esxi4 # 4th ESXi host to work with
export VSPHERE_ESXI_HOST5 ?= esxi5 # 5th ESXi host to work with
export VSPHERE_ESXI_HOST6 ?= esxi6 # 6th ESXi host to work with
export VSPHERE_ESXI_HOST7 ?= esxi7 # 7th ESXi host to work with
export VSPHERE_HOST_NIC0 ?= vmnic0 # NIC0 for host net tests
export VSPHERE_HOST_NIC1 ?= vmnic1 # NIC1 for host net tests
export VSPHERE_VMFS_EXPECTED ?= scsi-name # Name of expected SCSI disk
export VSPHERE_VMFS_REGEXP ?= expr # Regexp for SCSI disk search
export VSPHERE_DS_VMFS_DISK0 ?= scsi-name0 # 1st disk for vmfs_datastore
export VSPHERE_DS_VMFS_DISK1 ?= scsi-name1 # 2nd disk for vmfs_datastore
export VSPHERE_DS_VMFS_DISK2 ?= scsi-name2 # 3rd disk for vmfs_datastore
export VSPHERE_DS_FOLDER ?= ds-folder # Path to a datastore folder
export VSPHERE_NAS_HOST ?= nas-host # Hostname for nas_datastore
export VSPHERE_NFS_PATH ?= nfs-path # NFS path for nas_datastore
export VSPHERE_NFS_PATH2 ?= nfs-path # 2nd nas_datastore path
export VSPHERE_FOLDER_V0_PATH ?= old-folder # vsphere_folder state test
export VSPHERE_ISO_FILE ?= iso-file # ISO file for CDROM device
export VSPHERE_ISO_DATASTORE ?= iso-ds # ISO file for CDROM device
export VSPHERE_VM_V1_PATH ?= vm-path # VM resource state migration
export VSPHERE_VAPP_CONTAINER ?= vapp-path # Path to a vApp container
export VSPHERE_PERSIST_SESSION ?= true # Session persistence
export VSPHERE_REST_SESSION_PATH ?= rest-path # Path to store rest sessions
export VSPHERE_VIM_SESSION_PATH ?= vim-path # Path to store vim sessions
export VSPHERE_VAPP_RESOURCE_POOL ?= vapp-rp-path #vSphere path to vApp's resource pool
export VSPHERE_CLONED_VM_DISK_SIZE ?= =32 # Size of disk attached to a cloned VM
export VSPHERE_CLONED_VM_DISK_SIZE ?= 32 # Size of disk attached to a cloned VM
export VSPHERE_STORAGE_POLICY ?= sp-test # Name of a vm storage policy

# vi: filetype=make
31 changes: 31 additions & 0 deletions vsphere/data_source_vsphere_storage_policy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package vsphere

import (
"github.com/hashicorp/terraform/helper/schema"
"github.com/terraform-providers/terraform-provider-vsphere/vsphere/internal/helper/spbm"
)

func dataSourceVSphereStoragePolicy() *schema.Resource {
return &schema.Resource{
Read: dataSourceVSphereStoragePolicyRead,
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Description: "The display name of the storage policy.",
Required: true,
},
},
}
}

func dataSourceVSphereStoragePolicyRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*VSphereClient).vimClient

id, err := spbm.PolicyIDByName(client, d.Get("name").(string))
if err != nil {
return err
}

d.SetId(id)
return nil
}
49 changes: 49 additions & 0 deletions vsphere/data_source_vsphere_storage_policy_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package vsphere

import (
"fmt"
"os"
"regexp"
"testing"

"github.com/hashicorp/terraform/helper/resource"
)

func TestAccDataSourceVSphereStoragePolicy_basic(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
testAccDataSourceVSphereStoragePolicyPreCheck(t)
testAccSkipIfEsxi(t)
},
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceVSphereStoragePolicyConfig(),
Check: resource.ComposeTestCheckFunc(
resource.TestMatchResourceAttr("data.vsphere_storage_policy.storage_policy", "id", regexp.MustCompile("^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$")),
),
},
},
})
}

func testAccDataSourceVSphereStoragePolicyPreCheck(t *testing.T) {
if os.Getenv("VSPHERE_STORAGE_POLICY") == "" {
t.Skip("set VSPHERE_STORAGE_POLICY to run vsphere_storage_policy acceptance tests")
}
}

func testAccDataSourceVSphereStoragePolicyConfig() string {
return fmt.Sprintf(`
variable "storage_policy" {
default = "%s"
}
data "vsphere_storage_policy" "storage_policy" {
name = "${var.storage_policy}"
}
`,
os.Getenv("VSPHERE_STORAGE_POLICY"),
)
}
142 changes: 142 additions & 0 deletions vsphere/internal/helper/spbm/spbm_helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package spbm

import (
"context"
"fmt"
"log"

"github.com/terraform-providers/terraform-provider-vsphere/vsphere/internal/helper/provider"
"github.com/terraform-providers/terraform-provider-vsphere/vsphere/internal/helper/viapi"
"github.com/vmware/govmomi"
"github.com/vmware/govmomi/pbm"
"github.com/vmware/govmomi/pbm/methods"
pbmtypes "github.com/vmware/govmomi/pbm/types"
"github.com/vmware/govmomi/vim25/types"
)

// pbmClientFromGovmomiClient creates a new pbm client from given govmomi client.
// Can we have it in govmomi client as a field similar to tag client?
// We should not create a new pbm client every time we need it.
func pbmClientFromGovmomiClient(ctx context.Context, client *govmomi.Client) (*pbm.Client, error) {
if err := viapi.ValidateVirtualCenter(client); err != nil {
return nil, err
}

pc, err := pbm.NewClient(ctx, client.Client)
return pc, err

}

// PolicyIDByName finds a SPBM storage policy by name and returns its ID.
func PolicyIDByName(client *govmomi.Client, name string) (string, error) {
ctx, cancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
defer cancel()
pc, err := pbmClientFromGovmomiClient(ctx, client)
if err != nil {
return "", err
}

return pc.ProfileIDByName(ctx, name)
}

// policyNameByID returns storage policy name by its ID.
func policyNameByID(client *govmomi.Client, id string) (string, error) {
ctx, cancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
defer cancel()
pc, err := pbmClientFromGovmomiClient(ctx, client)
if err != nil {
return "", err
}

log.Printf("[DEBUG] Retrieving contents of storage profiles by id: %s.", id)
profileId := []pbmtypes.PbmProfileId{
pbmtypes.PbmProfileId{
UniqueId: id,
},
}
policies, err := pc.RetrieveContent(ctx, profileId)
if err != nil {
return "", err
}

return policies[0].GetPbmProfile().Name, err
}

// PolicySpecByID creates and returns VirtualMachineDefinedProfileSpec by policy ID.
func PolicySpecByID(id string) []types.BaseVirtualMachineProfileSpec {
return []types.BaseVirtualMachineProfileSpec{
&types.VirtualMachineDefinedProfileSpec{
ProfileId: id,
},
}
}

// PolicyIDByVirtualDisk fetches the storage policy associated with a virtual disk.
func PolicyIDByVirtualDisk(client *govmomi.Client, vmMOID string, diskKey int) (string, error) {
ctx, cancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
defer cancel()
pc, err := pbmClientFromGovmomiClient(ctx, client)
if err != nil {
return "", err
}

pbmSOR := pbmtypes.PbmServerObjectRef{
ObjectType: "virtualDiskId",
Key: fmt.Sprintf("%s:%d", vmMOID, diskKey),
}

policies, err := queryAssociatedProfile(ctx, pc, pbmSOR)
if err != nil {
return "", err
}

// If no policy returned then virtual disk is not associated with a policy
if policies == nil || len(policies) == 0 {
return "", nil
}

return policies[0].UniqueId, nil
}

// PolicyIDByVirtualMachine fetches the storage policy associated with a virtual machine.
func PolicyIDByVirtualMachine(client *govmomi.Client, vmMOID string) (string, error) {
ctx, cancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
defer cancel()
pc, err := pbmClientFromGovmomiClient(ctx, client)
if err != nil {
return "", err
}

pbmSOR := pbmtypes.PbmServerObjectRef{
ObjectType: "virtualMachine",
Key: vmMOID,
}

policies, err := queryAssociatedProfile(ctx, pc, pbmSOR)
if err != nil {
return "", err
}

// If no policy returned then VM is not associated with a policy
if policies == nil || len(policies) == 0 {
return "", nil
}

return policies[0].UniqueId, nil
}

// queryAssociatedProfile returns the PbmProfileId of the storage policy associated with entity.
func queryAssociatedProfile(ctx context.Context, pc *pbm.Client, ref pbmtypes.PbmServerObjectRef) ([]pbmtypes.PbmProfileId, error) {
log.Printf("[DEBUG] queryAssociatedProfile: Retrieving storage policy of server object of type [%s] and key [%s].", ref.ObjectType, ref.Key)
req := pbmtypes.PbmQueryAssociatedProfile{
This: pc.ServiceContent.ProfileManager,
Entity: ref,
}

res, err := methods.PbmQueryAssociatedProfile(ctx, pc, &req)
if err != nil {
return nil, err
}

return res.Returnval, nil
}
Loading

0 comments on commit bc1eb53

Please sign in to comment.