Skip to content

Commit

Permalink
fix: properly import physical interfaces (#169)
Browse files Browse the repository at this point in the history
  • Loading branch information
skatsaounis authored Apr 17, 2024
1 parent 4a03d32 commit 44818cf
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 18 deletions.
2 changes: 1 addition & 1 deletion docs/resources/network_interface_physical.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,5 @@ Import is supported using the following syntax:

```shell
# A physical network interface can be imported using the machine identifier (system ID, hostname, or FQDN) and its own identifier (MAC address, name, or ID). e.g.
$ terraform import maas_network_interface_physical.virsh_vm1 vm1:eth0
$ terraform import maas_network_interface_physical.virsh_vm1 vm1/eth0
```
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# A physical network interface can be imported using the machine identifier (system ID, hostname, or FQDN) and its own identifier (MAC address, name, or ID). e.g.
$ terraform import maas_network_interface_physical.virsh_vm1 vm1:eth0
$ terraform import maas_network_interface_physical.virsh_vm1 vm1/eth0
22 changes: 6 additions & 16 deletions maas/resource_maas_network_interface_physical.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ func resourceMaasNetworkInterfacePhysical() *schema.Resource {
DeleteContext: resourceNetworkInterfacePhysicalDelete,
Importer: &schema.ResourceImporter{
StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
idParts := strings.Split(d.Id(), ":")
idParts := strings.Split(d.Id(), "/")
if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" {
return nil, fmt.Errorf("unexpected format of ID (%q), expected MACHINE:NETWORK_INTERFACE", d.Id())
return nil, fmt.Errorf("unexpected format of ID (%q), expected MACHINE/NETWORK_INTERFACE", d.Id())
}
client := meta.(*client.Client)
machine, err := getMachine(client, idParts[0])
Expand All @@ -34,18 +34,8 @@ func resourceMaasNetworkInterfacePhysical() *schema.Resource {
if err != nil {
return nil, err
}
tfState := map[string]interface{}{
"id": fmt.Sprintf("%v", n.ID),
"mac_address": n.MACAddress,
"machine": machine.SystemID,
"mtu": n.EffectiveMTU,
"name": n.Name,
"tags": n.Tags,
"vlan": n.VLAN.ID,
}
if err := setTerraformState(d, tfState); err != nil {
return nil, err
}
d.Set("machine", idParts[0])
d.SetId(strconv.Itoa(n.ID))
return []*schema.ResourceData{d}, nil
},
},
Expand Down Expand Up @@ -110,7 +100,7 @@ func resourceNetworkInterfacePhysicalCreate(ctx context.Context, d *schema.Resou
return diag.FromErr(err)
}
}
d.SetId(fmt.Sprintf("%v", networkInterface.ID))
d.SetId(strconv.Itoa(networkInterface.ID))

return resourceNetworkInterfacePhysicalRead(ctx, d, meta)
}
Expand Down Expand Up @@ -210,7 +200,7 @@ func findNetworkInterfacePhysical(client *client.Client, machineSystemID string,
if n.Type != "physical" {
continue
}
if n.MACAddress == identifier || n.Name == identifier || fmt.Sprintf("%v", n.ID) == identifier {
if n.MACAddress == identifier || n.Name == identifier || strconv.Itoa(n.ID) == identifier {
return &n, nil
}
}
Expand Down
170 changes: 170 additions & 0 deletions maas/resource_maas_network_interface_physical_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package maas_test

import (
"fmt"
"os"
"strconv"
"strings"
"terraform-provider-maas/maas/testutils"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
"github.com/maas/gomaasclient/client"
"github.com/maas/gomaasclient/entity"
)

func testAccMaasNetworkInterfacePhysical(name string, machine string, fabric string) string {
return fmt.Sprintf(`
data "maas_fabric" "default" {
name = "%s"
}
data "maas_machine" "machine" {
hostname = "%s"
}
data "maas_vlan" "default" {
fabric = data.maas_fabric.default.id
vlan = 0
}
resource "maas_network_interface_physical" "test" {
machine = data.maas_machine.machine.id
name = "%s"
mac_address = "01:12:34:56:78:9A"
mtu = 9000
tags = ["tag1", "tag2"]
vlan = data.maas_vlan.default.id
}
`, fabric, machine, name)
}

func TestAccResourceMaasNetworkInterfacePhysical_basic(t *testing.T) {

var networkInterfacePhysical entity.NetworkInterface
name := acctest.RandomWithPrefix("tf-network-interface-physical")
machine := os.Getenv("TF_ACC_NETWORK_INTERFACE_MACHINE")
fabric := os.Getenv("TF_ACC_FABRIC")

checks := []resource.TestCheckFunc{
testAccMaasNetworkInterfacePhysicalCheckExists("maas_network_interface_physical.test", &networkInterfacePhysical),
resource.TestCheckResourceAttr("maas_network_interface_physical.test", "name", name),
resource.TestCheckResourceAttr("maas_network_interface_physical.test", "mac_address", "01:12:34:56:78:9A"),
resource.TestCheckResourceAttr("maas_network_interface_physical.test", "mtu", "9000"),
resource.TestCheckResourceAttr("maas_network_interface_physical.test", "tags.#", "2"),
resource.TestCheckResourceAttr("maas_network_interface_physical.test", "tags.0", "tag1"),
resource.TestCheckResourceAttr("maas_network_interface_physical.test", "tags.1", "tag2"),
resource.TestCheckResourceAttrPair("maas_network_interface_physical.test", "vlan", "data.maas_vlan.default", "id"),
}

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testutils.PreCheck(t, []string{"TF_ACC_NETWORK_INTERFACE_MACHINE", "TF_ACC_FABRIC"}) },
Providers: testutils.TestAccProviders,
CheckDestroy: testAccCheckMaasNetworkInterfacePhysicalDestroy,
ErrorCheck: func(err error) error { return err },
Steps: []resource.TestStep{
{
Config: testAccMaasNetworkInterfacePhysical(name, machine, fabric),
Check: resource.ComposeTestCheckFunc(checks...),
},
// Test import
{
ResourceName: "maas_network_interface_physical.test",
ImportState: true,
ImportStateVerify: true,
ImportStateIdFunc: func(s *terraform.State) (string, error) {
rs, ok := s.RootModule().Resources["maas_network_interface_physical.test"]
if !ok {
return "", fmt.Errorf("resource not found: %s", "maas_network_interface_physical.test")
}

if rs.Primary.ID == "" {
return "", fmt.Errorf("resource id not set")
}
return fmt.Sprintf("%s/%s", rs.Primary.Attributes["machine"], rs.Primary.Attributes["id"]), nil
},
},
// Test import by MAC Address
{
ResourceName: "maas_network_interface_physical.test",
ImportState: true,
ImportStateVerify: true,
ImportStateIdFunc: func(s *terraform.State) (string, error) {
rs, ok := s.RootModule().Resources["maas_network_interface_physical.test"]
if !ok {
return "", fmt.Errorf("resource not found: %s", "maas_network_interface_physical.test")
}

if rs.Primary.ID == "" {
return "", fmt.Errorf("resource id not set")
}
return fmt.Sprintf("%s/%s", rs.Primary.Attributes["machine"], rs.Primary.Attributes["mac_address"]), nil
},
},
},
})
}

func testAccMaasNetworkInterfacePhysicalCheckExists(rn string, networkInterfacePhysical *entity.NetworkInterface) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[rn]
if !ok {
return fmt.Errorf("resource not found: %s\n %#v", rn, s.RootModule().Resources)
}

if rs.Primary.ID == "" {
return fmt.Errorf("resource id not set")
}

conn := testutils.TestAccProvider.Meta().(*client.Client)
id, err := strconv.Atoi(rs.Primary.ID)
if err != nil {
return err
}
gotNetworkInterfacePhysical, err := conn.NetworkInterface.Get(rs.Primary.Attributes["machine"], id)
if err != nil {
return fmt.Errorf("error getting network interface physical: %s", err)
}

*networkInterfacePhysical = *gotNetworkInterfacePhysical

return nil
}
}

func testAccCheckMaasNetworkInterfacePhysicalDestroy(s *terraform.State) error {
// retrieve the connection established in Provider configuration
conn := testutils.TestAccProvider.Meta().(*client.Client)

// loop through the resources in state, verifying each maas_network_interface_physical
// is destroyed
for _, rs := range s.RootModule().Resources {
if rs.Type != "maas_network_interface_physical" {
continue
}

// Retrieve our maas_network_interface_physical by referencing it's state ID for API lookup
id, err := strconv.Atoi(rs.Primary.ID)
if err != nil {
return err
}
response, err := conn.NetworkInterface.Get(rs.Primary.Attributes["machine"], id)
if err == nil {
if response != nil && response.ID == id {
return fmt.Errorf("MAAS Network interface physical (%s) still exists.", rs.Primary.ID)
}

return nil
}

// If the error is equivalent to 404 not found, the maas_network_interface_physical is destroyed.
// Otherwise return the error
if !strings.Contains(err.Error(), "404 Not Found") {
return err
}
}

return nil
}

0 comments on commit 44818cf

Please sign in to comment.