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.
Merge pull request hashicorp#126 from jorgenunez/new-resource-datacenter
Enhancement: New resource datacenter
- Loading branch information
Showing
5 changed files
with
338 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,169 @@ | ||
package vsphere | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"time" | ||
|
||
"github.com/hashicorp/terraform/helper/resource" | ||
"github.com/hashicorp/terraform/helper/schema" | ||
"github.com/vmware/govmomi" | ||
"github.com/vmware/govmomi/find" | ||
"github.com/vmware/govmomi/object" | ||
"github.com/vmware/govmomi/vim25/methods" | ||
"github.com/vmware/govmomi/vim25/types" | ||
"golang.org/x/net/context" | ||
) | ||
|
||
func resourceVSphereDatacenter() *schema.Resource { | ||
return &schema.Resource{ | ||
Create: resourceVSphereDatacenterCreate, | ||
Read: resourceVSphereDatacenterRead, | ||
Delete: resourceVSphereDatacenterDelete, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"name": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
}, | ||
"folder": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Optional: true, | ||
ForceNew: true, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func resourceVSphereDatacenterCreate(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*govmomi.Client) | ||
name := d.Get("name").(string) | ||
|
||
var f *object.Folder | ||
if v, ok := d.GetOk("folder"); ok { | ||
finder := find.NewFinder(client.Client, true) | ||
var err error | ||
f, err = finder.Folder(context.TODO(), v.(string)) | ||
if err != nil { | ||
return fmt.Errorf("failed to find folder that will contain the datacenter: %s", err) | ||
} | ||
} else { | ||
f = object.NewRootFolder(client.Client) | ||
} | ||
|
||
dc, err := f.CreateDatacenter(context.TODO(), name) | ||
if err != nil || dc == nil { | ||
return fmt.Errorf("failed to create datacenter: %s", err) | ||
} | ||
// From govmomi code: "Response will be nil if this is an ESX host that does not belong to a vCenter" | ||
if dc == nil { | ||
return fmt.Errorf("ESX host does not belong to a vCenter") | ||
} | ||
|
||
// Wait for the datacenter resource to be ready | ||
stateConf := &resource.StateChangeConf{ | ||
Pending: []string{"InProgress"}, | ||
Target: []string{"Created"}, | ||
Refresh: resourceVSphereDatacenterStateRefreshFunc(d, meta), | ||
Timeout: 10 * time.Minute, | ||
MinTimeout: 3 * time.Second, | ||
Delay: 5 * time.Second, | ||
} | ||
|
||
_, err = stateConf.WaitForState() | ||
if err != nil { | ||
return fmt.Errorf("error waiting for datacenter (%s) to become ready: %s", name, err) | ||
} | ||
|
||
d.SetId(name) | ||
|
||
return resourceVSphereDatacenterRead(d, meta) | ||
|
||
} | ||
|
||
func resourceVSphereDatacenterStateRefreshFunc(d *schema.ResourceData, meta interface{}) resource.StateRefreshFunc { | ||
return func() (interface{}, string, error) { | ||
log.Print("[TRACE] Refreshing datacenter state") | ||
dc, err := datacenterExists(d, meta) | ||
if err != nil { | ||
switch err.(type) { | ||
case *find.NotFoundError: | ||
log.Printf("[TRACE] Refreshing state. Datacenter not found: %s", err) | ||
return nil, "InProgress", nil | ||
default: | ||
return nil, "Failed", err | ||
} | ||
} | ||
log.Print("[TRACE] Refreshing state. Datacenter found") | ||
return dc, "Created", nil | ||
} | ||
} | ||
|
||
func datacenterExists(d *schema.ResourceData, meta interface{}) (*object.Datacenter, error) { | ||
client := meta.(*govmomi.Client) | ||
name := d.Get("name").(string) | ||
|
||
path := name | ||
if v, ok := d.GetOk("folder"); ok { | ||
path = v.(string) + "/" + name | ||
} | ||
|
||
finder := find.NewFinder(client.Client, true) | ||
dc, err := finder.Datacenter(context.TODO(), path) | ||
return dc, err | ||
} | ||
|
||
func resourceVSphereDatacenterRead(d *schema.ResourceData, meta interface{}) error { | ||
_, err := datacenterExists(d, meta) | ||
if err != nil { | ||
log.Printf("couldn't find the specified datacenter: %s", err) | ||
d.SetId("") | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func resourceVSphereDatacenterDelete(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*govmomi.Client) | ||
name := d.Get("name").(string) | ||
|
||
path := name | ||
if v, ok := d.GetOk("folder"); ok { | ||
path = v.(string) + "/" + name | ||
} | ||
|
||
finder := find.NewFinder(client.Client, true) | ||
dc, err := finder.Datacenter(context.TODO(), path) | ||
if err != nil { | ||
log.Printf("couldn't find the specified datacenter: %s", err) | ||
d.SetId("") | ||
return nil | ||
} | ||
|
||
req := &types.Destroy_Task{ | ||
This: dc.Common.Reference(), | ||
} | ||
|
||
_, err = methods.Destroy_Task(context.TODO(), client, req) | ||
if err != nil { | ||
return fmt.Errorf("%s", err) | ||
} | ||
|
||
// Wait for the datacenter resource to be destroyed | ||
stateConf := &resource.StateChangeConf{ | ||
Pending: []string{"Created"}, | ||
Target: []string{}, | ||
Refresh: resourceVSphereDatacenterStateRefreshFunc(d, meta), | ||
Timeout: 10 * time.Minute, | ||
MinTimeout: 3 * time.Second, | ||
Delay: 5 * time.Second, | ||
} | ||
|
||
_, err = stateConf.WaitForState() | ||
if err != nil { | ||
return fmt.Errorf("error waiting for datacenter (%s) to become ready: %s", name, 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,126 @@ | ||
package vsphere | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform/helper/resource" | ||
"github.com/hashicorp/terraform/terraform" | ||
"github.com/vmware/govmomi" | ||
"github.com/vmware/govmomi/find" | ||
"golang.org/x/net/context" | ||
) | ||
|
||
const resourceName = "vsphere_datacenter.testDC" | ||
|
||
const testAccCheckVSphereDatacenterConfig = ` | ||
resource "vsphere_datacenter" "testDC" { | ||
name = "testDC" | ||
} | ||
` | ||
|
||
const testAccCheckVSphereDatacenterConfigSubfolder = ` | ||
resource "vsphere_datacenter" "testDC" { | ||
name = "testDC" | ||
folder = "%s" | ||
} | ||
` | ||
|
||
// Create a datacenter on the root folder | ||
func TestAccVSphereDatacenter_createOnRootFolder(t *testing.T) { | ||
|
||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
CheckDestroy: testAccCheckVSphereDatacenterDestroy, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccCheckVSphereDatacenterConfig, | ||
Check: resource.ComposeTestCheckFunc(testAccCheckVSphereDatacenterExists(resourceName, true)), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
// Create a datacenter on a subfolder | ||
func TestAccVSphereDatacenter_createOnSubfolder(t *testing.T) { | ||
dcFolder := os.Getenv("VSPHERE_DC_FOLDER") | ||
|
||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
CheckDestroy: testAccCheckVSphereDatacenterDestroy, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: fmt.Sprintf(testAccCheckVSphereDatacenterConfigSubfolder, dcFolder), | ||
Check: resource.ComposeTestCheckFunc(testAccCheckVSphereDatacenterExists(resourceName, true)), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccCheckVSphereDatacenterDestroy(s *terraform.State) error { | ||
client := testAccProvider.Meta().(*govmomi.Client) | ||
finder := find.NewFinder(client.Client, true) | ||
|
||
for _, rs := range s.RootModule().Resources { | ||
if rs.Type != "vsphere_datacenter" { | ||
continue | ||
} | ||
|
||
path := rs.Primary.Attributes["name"] | ||
if _, ok := rs.Primary.Attributes["folder"]; ok { | ||
path = rs.Primary.Attributes["folder"] + "/" + path | ||
} | ||
_, err := finder.Datacenter(context.TODO(), path) | ||
if err != nil { | ||
switch err.(type) { | ||
case *find.NotFoundError: | ||
fmt.Printf("Expected error received: %s\n", err) | ||
return nil | ||
default: | ||
return err | ||
} | ||
} else { | ||
return fmt.Errorf("datacenter '%s' still exists", path) | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func testAccCheckVSphereDatacenterExists(n string, exists bool) resource.TestCheckFunc { | ||
return func(s *terraform.State) error { | ||
rs, ok := s.RootModule().Resources[n] | ||
if !ok { | ||
return fmt.Errorf("resource not found: %s", n) | ||
} | ||
|
||
if rs.Primary.ID == "" { | ||
return fmt.Errorf("no ID is set") | ||
} | ||
|
||
client := testAccProvider.Meta().(*govmomi.Client) | ||
finder := find.NewFinder(client.Client, true) | ||
|
||
path := rs.Primary.Attributes["name"] | ||
if _, ok := rs.Primary.Attributes["folder"]; ok { | ||
path = rs.Primary.Attributes["folder"] + "/" + path | ||
} | ||
_, err := finder.Datacenter(context.TODO(), path) | ||
if err != nil { | ||
switch e := err.(type) { | ||
case *find.NotFoundError: | ||
if exists { | ||
return fmt.Errorf("datacenter does not exist: %s", e.Error()) | ||
} | ||
fmt.Printf("Expected error received: %s\n", e.Error()) | ||
return nil | ||
default: | ||
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,39 @@ | ||
--- | ||
layout: "vsphere" | ||
page_title: "VMware vSphere: vsphere_datacenter" | ||
sidebar_current: "docs-vsphere-resource-datacenter" | ||
description: |- | ||
Provides a VMware vSphere datacenter resource. This can be used as the primary container of inventory objects such as hosts and virtual machines. | ||
--- | ||
|
||
# vsphere\_datacenter | ||
|
||
Provides a VMware vSphere datacenter resource. This can be used as the primary container of inventory objects such as hosts and virtual machines. | ||
|
||
## Example Usages | ||
|
||
**Create datacenter on the root folder:** | ||
|
||
```hcl | ||
resource "vsphere_datacenter" "prod_datacenter" { | ||
name = "my_prod_datacenter" | ||
} | ||
``` | ||
|
||
**Create datacenter on a subfolder:** | ||
|
||
```hcl | ||
resource "vsphere_datacenter" "research_datacenter" { | ||
name = "my_research_datacenter" | ||
folder = "/research/" | ||
} | ||
``` | ||
|
||
## Argument Reference | ||
|
||
The following arguments are supported: | ||
|
||
* `name` - (Required) The name of the datacenter. This name needs to be unique within the folder. | ||
* `folder` - (Optional) The folder where the datacenter should be created. | ||
|
||
~> **NOTE**: Datacenters cannot be changed once they are created. Modifying any of these attributes will force a new resource! |
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