diff --git a/vsphere/resource_vsphere_vnic.go b/vsphere/resource_vsphere_vnic.go index 918c039ba..6c226d61d 100644 --- a/vsphere/resource_vsphere_vnic.go +++ b/vsphere/resource_vsphere_vnic.go @@ -11,6 +11,7 @@ import ( "strings" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-vsphere/vsphere/internal/helper/hostsystem" "github.com/hashicorp/terraform-provider-vsphere/vsphere/internal/helper/structure" "github.com/vmware/govmomi" @@ -133,12 +134,12 @@ func resourceVsphereNicRead(d *schema.ResourceData, meta interface{}) error { } // get enabled services - host_system, err := hostsystem.FromID(client, hostID) + hostSystem, err := hostsystem.FromID(client, hostID) if err != nil { return err } - hostVnicMgr, err := host_system.ConfigManager().VirtualNicManager(ctx) + hostVnicMgr, err := hostSystem.ConfigManager().VirtualNicManager(ctx) if err != nil { return nil } @@ -317,7 +318,10 @@ func BaseVMKernelSchema() map[string]*schema.Schema { Type: schema.TypeSet, Optional: true, Description: "Enabled services setting for this interface. Current possible values are 'vmotion', 'management' and 'vsan'", - Elem: &schema.Schema{Type: schema.TypeString}, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice(vnicServiceTypeAllowedValues, false), + }, }, } return sch @@ -357,17 +361,17 @@ func updateVNic(d *schema.ResourceData, meta interface{}) (string, error) { } func updateVnicService(d *schema.ResourceData, hostID string, nicID string, meta interface{}) error { - service_old, service_new := d.GetChange("services") - deleteList := service_old.(*schema.Set).List() - addList := service_new.(*schema.Set).List() + serviceOld, serviceNew := d.GetChange("services") + deleteList := serviceOld.(*schema.Set).List() + addList := serviceNew.(*schema.Set).List() client := meta.(*Client).vimClient ctx := context.TODO() - host_system, err := hostsystem.FromID(client, hostID) + hostSystem, err := hostsystem.FromID(client, hostID) if err != nil { return err } - method, err := host_system.ConfigManager().VirtualNicManager(ctx) + method, err := hostSystem.ConfigManager().VirtualNicManager(ctx) if err != nil { return nil } @@ -391,21 +395,7 @@ func updateVnicService(d *schema.ResourceData, hostID string, nicID string, meta func precheckEnableServices(d *schema.ResourceData) error { if d.Get("netstack").(string) != "defaultTcpipStack" && len(d.Get("services").(*schema.Set).List()) != 0 { - return fmt.Errorf("Services could be configured only when the netstack is set to defaultTcpipStack.") - } - // will expand scope later, current possible values are vmotion, management and vsan. - data := d.Get("services").(*schema.Set).List() - for _, value := range data { - isValueAllowed := false - for _, allowedValue := range vnicServiceTypeAllowedValues { - if value == allowedValue { - isValueAllowed = true - break - } - } - if !isValueAllowed { - return fmt.Errorf("%s is not an allowed service type.", value) - } + return fmt.Errorf("services can only be configured when netstack is set to defaultTcpipStack") } return nil } diff --git a/vsphere/resource_vsphere_vnic_test.go b/vsphere/resource_vsphere_vnic_test.go index c392dd39c..4d1269890 100644 --- a/vsphere/resource_vsphere_vnic_test.go +++ b/vsphere/resource_vsphere_vnic_test.go @@ -8,6 +8,7 @@ import ( "errors" "fmt" "os" + "regexp" "strconv" "strings" "testing" @@ -18,6 +19,8 @@ import ( "github.com/vmware/govmomi" ) +// TODO: move away from tests being composed in this manner + type genTfConfig func(string) string func generateSteps(cfgFunc genTfConfig, netstack string) []resource.TestStep { @@ -117,6 +120,117 @@ func TestAccResourceVSphereVNic_hvs_vmotion(t *testing.T) { }) } +func TestAccResourceVSphereVNic_services_nonDefaultNetstack(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { + RunSweepers() + testAccPreCheck(t) + }, + Providers: testAccProviders, + CheckDestroy: testAccVSphereVNicDestroy, + Steps: []resource.TestStep{ + { + Config: testaccvspherevnicconfigHvs( + combineSnippets( + ipv4Snippet("192.0.2.10|255.255.255.0|192.0.2.1"), + "", + netstackSnippet("vmotion"), + "", + `services = ["vsan"]`, + ), + ), + ExpectError: regexp.MustCompile("services can only be configured when netstack is set to defaultTcpipStack"), + }, + }, + }) +} + +func TestAccResourceVSphereVNic_services_invalid(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { + RunSweepers() + testAccPreCheck(t) + }, + Providers: testAccProviders, + CheckDestroy: testAccVSphereVNicDestroy, + Steps: []resource.TestStep{ + { + Config: testaccvspherevnicconfigHvs( + combineSnippets( + ipv4Snippet("192.0.2.10|255.255.255.0|192.0.2.1"), + "", + netstackSnippet("defaultTcpipStack"), + "", + `services = ["invalid"]`, + ), + ), + ExpectError: regexp.MustCompile("Error"), + PlanOnly: true, + }, + }, + }) +} + +func TestAccResourceVSphereVNic_services_valid(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { + RunSweepers() + testAccPreCheck(t) + }, + Providers: testAccProviders, + CheckDestroy: testAccVSphereVNicDestroy, + Steps: []resource.TestStep{ + { + Config: testaccvspherevnicconfigHvs( + combineSnippets( + ipv4Snippet("192.0.2.10|255.255.255.0|192.0.2.1"), + "", + netstackSnippet("defaultTcpipStack"), + "", + `services = ["vsan"]`, + ), + ), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("vsphere_vnic.v1", "services.#", "1"), + resource.TestCheckTypeSetElemAttr("vsphere_vnic.v1", "services.*", "vsan"), + ), + }, + { + Config: testaccvspherevnicconfigHvs( + combineSnippets( + ipv4Snippet("192.0.2.10|255.255.255.0|192.0.2.1"), + "", + netstackSnippet("defaultTcpipStack"), + "", + `services = ["vmotion"]`, + ), + ), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("vsphere_vnic.v1", "services.#", "1"), + resource.TestCheckTypeSetElemAttr("vsphere_vnic.v1", "services.*", "vmotion"), + ), + }, + { + Config: testaccvspherevnicconfigHvs( + combineSnippets( + ipv4Snippet("192.0.2.10|255.255.255.0|192.0.2.1"), + "", + netstackSnippet("defaultTcpipStack"), + "", + `services = ["vmotion", "management", "vsan"]`, + ), + ), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("vsphere_vnic.v1", "services.#", "3"), + resource.TestCheckTypeSetElemAttr("vsphere_vnic.v1", "services.*", "vmotion"), + resource.TestCheckTypeSetElemAttr("vsphere_vnic.v1", "services.*", "management"), + resource.TestCheckTypeSetElemAttr("vsphere_vnic.v1", "services.*", "vsan"), + ), + }, + }, + }) +} + func testAccVsphereVNicNetworkSettings(name, ipv4State, ipv6State, netstack string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[name]