Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

r/virtual_machine: add vApp properties #303

Merged
merged 23 commits into from
Jan 13, 2018
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
fe8c313
Add VApp properties to r/virtual_machine
rowanjacobs Dec 8, 2017
812d2d3
Nest properties under top-level vApp subresource
rowanjacobs Dec 8, 2017
53925ef
Test updating and removing vapp properties
mcwumbly Dec 8, 2017
050919e
support empty vapp and vapp.properties blocks
rowanjacobs Dec 13, 2017
6cc04ab
Return *VmConfigSpec instead of BaseVmConfigSpec
rowanjacobs Jan 2, 2018
3e1d394
Use CoreOS OVA for testing
rowanjacobs Jan 2, 2018
8017ae4
Get old vApp properties from VM template
rowanjacobs Jan 2, 2018
817a852
zero out unset properties
rowanjacobs Jan 3, 2018
c27efe4
respect nonempty default values set in vapp properties
rowanjacobs Jan 3, 2018
31881de
Read all non-default vapp property values
desmondrawls Jan 3, 2018
4cb7e4f
Move vapp to schemaVirtualMachineConfigSpec
rowanjacobs Jan 3, 2018
032d70c
Reboot required for change in vApp config
rowanjacobs Jan 8, 2018
dfb9168
Don't need to loop over new vApp map values
rowanjacobs Jan 11, 2018
3170e96
Unsupported vApp properties throw an error
Jan 12, 2018
de8cf26
Spelling
rowanjacobs Jan 12, 2018
4cc701b
r/virtual_machine: Roll back clones on errors with config expansion
vancluever Jan 12, 2018
eb013b2
r/virtual_machine: Block vApp properties on from-scratch scenarios
vancluever Jan 12, 2018
c3fd7da
r/virtual_machine: Fix a couple of golint issues
vancluever Jan 12, 2018
c309d3c
r/virtual_machine: Document new vApp functionality
vancluever Jan 12, 2018
646758c
Merge branch 'master' into rowanjacobs/master
vancluever Jan 12, 2018
b19e6d3
r/virtual_machine: vApp tests use CoreOS template
vancluever Jan 12, 2018
ab73496
r/virtual_machine: Fix tests
vancluever Jan 12, 2018
ca780b0
r/virtual_machine: Add vApp property failure tests
vancluever Jan 13, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions vsphere/resource_vsphere_virtual_machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,13 @@ func resourceVSphereVirtualMachine() *schema.Resource {
MaxItems: 1,
Elem: &schema.Resource{Schema: vmworkflow.VirtualMachineCloneSchema()},
},
"vapp": {
Type: schema.TypeList,
Optional: true,
Description: "vApp configuration data for this virtual machine. Can be used to provide configuration data for OVF images.",
MaxItems: 1,
Elem: &schema.Resource{Schema: VAppSubresourceSchema()},
},
"reboot_required": {
Type: schema.TypeBool,
Computed: true,
Expand Down Expand Up @@ -192,6 +199,21 @@ func resourceVSphereVirtualMachine() *schema.Resource {
}
}

// VAppSchema represents the schema for the vApp sub-resource.
//
// This sub-resource allows the customization of vApp properties
// on cloned VMs.
func VAppSubresourceSchema() map[string]*schema.Schema {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we could probably just put this directly into schemaVirtualMachineConfigSpec as it's so small, along with the vapp key. I'm almost tempted to also just say we flatten it and name it vapp_properties, but we might need to add more keys at a later time.

return map[string]*schema.Schema{
"properties": {
Type: schema.TypeMap,
Optional: true,
Description: "A map of customizable vApp properties and their values. Allows customization of VMs cloned from OVF templates which have customizable vApp properties.",
Elem: schema.TypeString,
},
}
}

func resourceVSphereVirtualMachineCreate(d *schema.ResourceData, meta interface{}) error {
log.Printf("[DEBUG] %s: Beginning create", resourceVSphereVirtualMachineIDString(d))
client := meta.(*VSphereClient).vimClient
Expand Down
224 changes: 224 additions & 0 deletions vsphere/resource_vsphere_virtual_machine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,45 @@ func TestAccResourceVSphereVirtualMachine(t *testing.T) {
},
},
},
{
"clone with vapp properties",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some thoughts on testing this while enforcing present keys only - we might need to test this against a CoreOS template or something else well known, and work on setting well-known cloud-config keys.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've started testing against the CoreOS OVA instead of against a custom-built template.

resource.TestCase{
PreCheck: func() {
testAccPreCheck(tp)
testAccResourceVSphereVirtualMachinePreCheck(tp)
},
Providers: testAccProviders,
CheckDestroy: testAccResourceVSphereVirtualMachineCheckExists(false),
Steps: []resource.TestStep{
{
Config: testAccResourceVSphereVirtualMachineConfigCloneWithVAppProperties(),
Check: resource.ComposeTestCheckFunc(
testAccResourceVSphereVirtualMachineCheckExists(true),
testAccResourceVSphereVirtualMachineCheckVAppConfigKey("example_key", "example value"),
testAccResourceVSphereVirtualMachineCheckVAppConfigKey("another_key", ""),
),
},
{
Config: testAccResourceVSphereVirtualMachineConfigCloneUpdatingVAppProperties(),
Check: resource.ComposeTestCheckFunc(
testAccResourceVSphereVirtualMachineCheckExists(true),
testAccResourceVSphereVirtualMachineCheckVAppConfigKey("another_key", "another value"),
testAccResourceVSphereVirtualMachineCheckVAppConfigKey("example_key", "new value"),
),
},
// This test is commented out because removing a value does not work with the current implementation.
// This seems like it may be a limitation of the vSphere API or or client implementation.
// {
// Config: testAccResourceVSphereVirtualMachineConfigCloneWithVAppProperties(),
// Check: resource.ComposeTestCheckFunc(
// testAccResourceVSphereVirtualMachineCheckExists(true),
// testAccResourceVSphereVirtualMachineCheckVAppConfigKey("example_key", "example value"),
// testAccResourceVSphereVirtualMachineCheckVAppConfigKey("another_key", ""),
// ),
// },
},
},
},
{
"cpu hot add",
resource.TestCase{
Expand Down Expand Up @@ -1285,6 +1324,22 @@ func testAccResourceVSphereVirtualMachineCheckExists(expected bool) resource.Tes
}
}

func testAccResourceVSphereVirtualMachineCheckVAppConfigKey(key, value string) resource.TestCheckFunc {
return func(s *terraform.State) error {
props, err := testGetVirtualMachineProperties(s, "vm")
if err != nil {
return err
}
actual := props.Config.VAppConfig.GetVmConfigInfo().Property
for _, prop := range actual {
if prop.Id == key && prop.Value != value {
return fmt.Errorf("expected vAppConfig property %s to have value %s, got %s", key, value, prop.Value)
}
}
return nil
}
}

// testAccResourceVSphereVirtualMachineCheckPowerState is a check to check for
// a VirtualMachine's power state.
func testAccResourceVSphereVirtualMachineCheckPowerState(expected types.VirtualMachinePowerState) resource.TestCheckFunc {
Expand Down Expand Up @@ -5730,3 +5785,172 @@ resource "vsphere_virtual_machine" "vm" {
os.Getenv("VSPHERE_USE_LINKED_CLONE"),
)
}

func testAccResourceVSphereVirtualMachineConfigCloneWithVAppProperties() string {
return fmt.Sprintf(`
variable "datacenter" {
default = "%s"
}

variable "resource_pool" {
default = "%s"
}

variable "network_label" {
default = "%s"
}

variable "datastore" {
default = "%s"
}

variable "template" {
default = "%s"
}

data "vsphere_datacenter" "dc" {
name = "${var.datacenter}"
}

data "vsphere_datastore" "datastore" {
name = "${var.datastore}"
datacenter_id = "${data.vsphere_datacenter.dc.id}"
}

data "vsphere_resource_pool" "pool" {
name = "${var.resource_pool}"
datacenter_id = "${data.vsphere_datacenter.dc.id}"
}

data "vsphere_network" "network" {
name = "${var.network_label}"
datacenter_id = "${data.vsphere_datacenter.dc.id}"
}

data "vsphere_virtual_machine" "template" {
name = "${var.template}"
datacenter_id = "${data.vsphere_datacenter.dc.id}"
}

resource "vsphere_virtual_machine" "vm" {
name = "terraform-test"
resource_pool_id = "${data.vsphere_resource_pool.pool.id}"
datastore_id = "${data.vsphere_datastore.datastore.id}"

num_cpus = 2
memory = 2048
guest_id = "${data.vsphere_virtual_machine.template.guest_id}"

network_interface {
network_id = "${data.vsphere_network.network.id}"
adapter_type = "${data.vsphere_virtual_machine.template.network_interface_types[0]}"
}

disk {
name = "terraform-test.vmdk"
size = "${data.vsphere_virtual_machine.template.disks.0.size}"
}

vapp {
properties {
example_key = "example value"
}
}

clone {
template_uuid = "${data.vsphere_virtual_machine.template.id}"
}
}
`,
os.Getenv("VSPHERE_DATACENTER"),
os.Getenv("VSPHERE_RESOURCE_POOL"),
os.Getenv("VSPHERE_NETWORK_LABEL"),
os.Getenv("VSPHERE_DATASTORE"),
os.Getenv("VSPHERE_TEMPLATE"),
)
}

func testAccResourceVSphereVirtualMachineConfigCloneUpdatingVAppProperties() string {
return fmt.Sprintf(`
variable "datacenter" {
default = "%s"
}

variable "resource_pool" {
default = "%s"
}

variable "network_label" {
default = "%s"
}

variable "datastore" {
default = "%s"
}

variable "template" {
default = "%s"
}

data "vsphere_datacenter" "dc" {
name = "${var.datacenter}"
}

data "vsphere_datastore" "datastore" {
name = "${var.datastore}"
datacenter_id = "${data.vsphere_datacenter.dc.id}"
}

data "vsphere_resource_pool" "pool" {
name = "${var.resource_pool}"
datacenter_id = "${data.vsphere_datacenter.dc.id}"
}

data "vsphere_network" "network" {
name = "${var.network_label}"
datacenter_id = "${data.vsphere_datacenter.dc.id}"
}

data "vsphere_virtual_machine" "template" {
name = "${var.template}"
datacenter_id = "${data.vsphere_datacenter.dc.id}"
}

resource "vsphere_virtual_machine" "vm" {
name = "terraform-test"
resource_pool_id = "${data.vsphere_resource_pool.pool.id}"
datastore_id = "${data.vsphere_datastore.datastore.id}"

num_cpus = 2
memory = 2048
guest_id = "${data.vsphere_virtual_machine.template.guest_id}"

network_interface {
network_id = "${data.vsphere_network.network.id}"
adapter_type = "${data.vsphere_virtual_machine.template.network_interface_types[0]}"
}

disk {
name = "terraform-test.vmdk"
size = "${data.vsphere_virtual_machine.template.disks.0.size}"
}

vapp {
properties {
another_key = "another value"
example_key = "new value"
}
}

clone {
template_uuid = "${data.vsphere_virtual_machine.template.id}"
}
}
`,
os.Getenv("VSPHERE_DATACENTER"),
os.Getenv("VSPHERE_RESOURCE_POOL"),
os.Getenv("VSPHERE_NETWORK_LABEL"),
os.Getenv("VSPHERE_DATASTORE"),
os.Getenv("VSPHERE_TEMPLATE"),
)
}
Loading