Skip to content

Commit

Permalink
Merge pull request hashicorp#146 from terraform-providers/f-host-data…
Browse files Browse the repository at this point in the history
…-source

New data source: vsphere_host
  • Loading branch information
vancluever authored Aug 31, 2017
2 parents c4e803d + f06f4a8 commit 5ea05e1
Show file tree
Hide file tree
Showing 9 changed files with 271 additions and 7 deletions.
46 changes: 46 additions & 0 deletions vsphere/data_source_vsphere_host.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package vsphere

import (
"fmt"

"github.com/hashicorp/terraform/helper/schema"
"github.com/vmware/govmomi"
)

func dataSourceVSphereHost() *schema.Resource {
return &schema.Resource{
Read: dataSourceVSphereHostRead,

Schema: map[string]*schema.Schema{
"name": &schema.Schema{
Type: schema.TypeString,
Description: "The name of the host. This can be a name or path. If not provided, the default host is used.",
Optional: true,
},
"datacenter_id": &schema.Schema{
Type: schema.TypeString,
Description: "The managed object ID of the datacenter to look for the host in.",
Required: true,
},
},
}
}

func dataSourceVSphereHostRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*govmomi.Client)
name := d.Get("name").(string)
dcID := d.Get("datacenter_id").(string)
dc, err := datacenterFromID(client, dcID)
if err != nil {
return fmt.Errorf("error fetching datacenter: %s", err)
}
hs, err := hostSystemOrDefault(client, name, dc)
if err != nil {
return fmt.Errorf("error fetching host: %s", err)
}

id := hs.Reference().Value
d.SetId(id)

return nil
}
108 changes: 108 additions & 0 deletions vsphere/data_source_vsphere_host_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package vsphere

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

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

func TestAccDataSourceVSphereHost(t *testing.T) {
var tp *testing.T
testAccDataSourceVSphereHostCases := []struct {
name string
testCase resource.TestCase
}{
{
"basic",
resource.TestCase{
PreCheck: func() {
testAccPreCheck(tp)
testAccDataSourceVSphereHostPreCheck(tp)
},
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceVSphereHostConfig(),
Check: resource.ComposeTestCheckFunc(
resource.TestMatchResourceAttr(
"data.vsphere_host.host",
"id",
testAccDataSourceVSphereHostExpectedRegexp(),
),
),
},
},
},
},
{
"default",
resource.TestCase{
PreCheck: func() {
testAccPreCheck(tp)
testAccDataSourceVSphereHostPreCheck(tp)
testAccSkipIfNotEsxi(tp)
},
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceVSphereHostConfigDefault,
Check: resource.ComposeTestCheckFunc(
resource.TestMatchResourceAttr(
"data.vsphere_host.host",
"id",
testAccDataSourceVSphereHostExpectedRegexp(),
),
),
},
},
},
},
}

for _, tc := range testAccDataSourceVSphereHostCases {
t.Run(tc.name, func(t *testing.T) {
tp = t
resource.Test(t, tc.testCase)
})
}
}

func testAccDataSourceVSphereHostPreCheck(t *testing.T) {
if os.Getenv("VSPHERE_DATACENTER") == "" {
t.Skip("set VSPHERE_DATACENTER to run vsphere_host acceptance tests")
}
if os.Getenv("VSPHERE_ESXI_HOST") == "" {
t.Skip("set VSPHERE_ESXI_HOST to run vsphere_host acceptance tests")
}
}

func testAccDataSourceVSphereHostExpectedRegexp() *regexp.Regexp {
if os.Getenv("VSPHERE_TEST_ESXI") != "" {
return regexp.MustCompile("^ha-host$")
}
return regexp.MustCompile("^host-")
}

func testAccDataSourceVSphereHostConfig() string {
return fmt.Sprintf(`
data "vsphere_datacenter" "dc" {
name = "%s"
}
data "vsphere_host" "host" {
name = "%s"
datacenter_id = "${data.vsphere_datacenter.dc.id}"
}
`, os.Getenv("VSPHERE_DATACENTER"), os.Getenv("VSPHERE_ESXI_HOST"))
}

const testAccDataSourceVSphereHostConfigDefault = `
data "vsphere_datacenter" "dc" {}
data "vsphere_host" "host" {
datacenter_id = "${data.vsphere_datacenter.dc.id}"
}
`
19 changes: 19 additions & 0 deletions vsphere/datacenter_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/vmware/govmomi"
"github.com/vmware/govmomi/find"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vim25/types"
"golang.org/x/net/context"
)

Expand All @@ -28,3 +29,21 @@ func getDatacenter(c *govmomi.Client, dc string) (*object.Datacenter, error) {
}
return nil, fmt.Errorf("unsupported ApiType: %s", t)
}

// datacenterFromID locates a Datacenter by its managed object reference ID.
func datacenterFromID(client *govmomi.Client, id string) (*object.Datacenter, error) {
finder := find.NewFinder(client.Client, false)

ref := types.ManagedObjectReference{
Type: "Datacenter",
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 datacenter with id: %s: %s", id, err)
}
return ds.(*object.Datacenter), nil
}
13 changes: 13 additions & 0 deletions vsphere/helper_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package vsphere

import (
"os"
"testing"
)

// testAccSkipIfNotEsxi skips a test if VSPHERE_TEST_ESXI is not set.
func testAccSkipIfNotEsxi(t *testing.T) {
if os.Getenv("VSPHERE_TEST_ESXI") == "" {
t.Skip("set VSPHERE_TEST_ESXI to run ESXi-specific acceptance tests")
}
}
32 changes: 32 additions & 0 deletions vsphere/host_system_helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package vsphere

import (
"context"
"fmt"

"github.com/vmware/govmomi"
"github.com/vmware/govmomi/find"
"github.com/vmware/govmomi/object"
)

// hostSystemOrDefault returns a HostSystem from a specific host name and
// datacenter. If the user is connecting over ESXi, the default host system is
// used.
func hostSystemOrDefault(client *govmomi.Client, name string, dc *object.Datacenter) (*object.HostSystem, error) {
finder := find.NewFinder(client.Client, false)
finder.SetDatacenter(dc)

ctx, cancel := context.WithTimeout(context.Background(), defaultAPITimeout)
defer cancel()
t := client.ServiceContent.About.ApiType
switch t {
case "HostAgent":
return finder.DefaultHostSystem(ctx)
case "VirtualCenter":
if name != "" {
return finder.HostSystem(ctx, name)
}
return finder.DefaultHostSystem(ctx)
}
return nil, fmt.Errorf("unsupported ApiType: %s", t)
}
6 changes: 6 additions & 0 deletions vsphere/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@ package vsphere

import (
"fmt"
"time"

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

// defaultAPITimeout is a default timeout value that is passed to functions
// requiring contexts, and other various waiters.
var defaultAPITimeout = time.Minute * 5

// Provider returns a terraform.ResourceProvider.
func Provider() terraform.ResourceProvider {
return &schema.Provider{
Expand Down Expand Up @@ -74,6 +79,7 @@ func Provider() terraform.ResourceProvider {

DataSourcesMap: map[string]*schema.Resource{
"vsphere_datacenter": dataSourceVSphereDatacenter(),
"vsphere_host": dataSourceVSphereHost(),
},

ConfigureFunc: providerConfigure,
Expand Down
8 changes: 1 addition & 7 deletions vsphere/resource_vsphere_license_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func TestAccVSphereLicenseWithLabelsOnESXiServer(t *testing.T) {
PreCheck: func() {
testAccPreCheck(t)
testAccVSpherePreLicenseBasicCheck(t)
testAccVspherePreLicenseESXiServerIsSetCheck(t)
testAccSkipIfNotEsxi(t)
},
Providers: testAccProviders,
Steps: []resource.TestStep{
Expand All @@ -109,12 +109,6 @@ func testAccVspherePreLicenseESXiServerIsNotSetCheck(t *testing.T) {
t.Skip("VSPHERE_TEST_ESXI must not be set for this acceptance test")
}
}
func testAccVspherePreLicenseESXiServerIsSetCheck(t *testing.T) {
key, err := strconv.ParseBool(os.Getenv("VSPHERE_TEST_ESXI"))
if err != nil || !key {
t.Skip("VSPHERE_TEST_ESXI must be set to true for this acceptance test")
}
}

func testAccVSphereLicenseWithLabelConfig() string {
return fmt.Sprintf(`
Expand Down
43 changes: 43 additions & 0 deletions website/docs/d/host.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
layout: "vsphere"
page_title: "VMware vSphere: vsphere_host"
sidebar_current: "docs-vsphere-data-source-host"
description: |-
A data source that can be used to get the ID of a host.
---

# vsphere\_host

The `vsphere_host` data source can be used to discover the ID of a vSphere
host. This can then be used with resources or data sources that require a host
managed object reference ID.

## Example Usage

```hcl
data "vsphere_datacenter" "datacenter" {
name = "dc1"
}
data "vsphere_host" "host" {
name = "esxi1"
datacenter_id = "${data.vsphere_datacenter.datacenter.id}"
}
```

## Argument Reference

The following arguments are supported:

* `name` - (String) The name of the host. This can be a name or path. Can be
omitted if there is only one host in your inventory.
* `datacenter_id` - (String, required) The managed object reference ID of a
datacenter.

~> **NOTE:** When used against an ESXi host directly, this data source _always_
fetches the server's host object ID, regardless of what is entered into `name`.

## Attribute Reference

The only exported attribute is `id`, which is the managed object ID of this
host.
3 changes: 3 additions & 0 deletions website/vsphere.erb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
<li<%= sidebar_current("docs-vsphere-data-source-datacenter") %>>
<a href="/docs/providers/vsphere/d/datacenter.html">vsphere_datacenter</a>
</li>
<li<%= sidebar_current("docs-vsphere-data-source-host") %>>
<a href="/docs/providers/vsphere/d/host.html">vsphere_host</a>
</li>
</ul>
</li>

Expand Down

0 comments on commit 5ea05e1

Please sign in to comment.