generated from hashicorp/terraform-provider-scaffolding
-
Notifications
You must be signed in to change notification settings - Fork 141
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add netbox_virtual_chassis resource
This adds support to manage virtual chassis. Adding members and setting the master will be done on the device resource itself, otherwise this would introduce circular dependencies.
- Loading branch information
Showing
5 changed files
with
340 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
--- | ||
# generated by https://github.com/fbreckle/terraform-plugin-docs | ||
page_title: "netbox_virtual_chassis Resource - terraform-provider-netbox" | ||
subcategory: "Data Center Inventory Management (DCIM)" | ||
description: |- | ||
From the official documentation https://docs.netbox.dev/en/stable/features/devices-cabling/#virtual-chassis: | ||
> Sometimes it is necessary to model a set of physical devices as sharing a single management plane. Perhaps the most common example of such a scenario is stackable switches. These can be modeled as virtual chassis in NetBox, with one device acting as the chassis master and the rest as members. All components of member devices will appear on the master. | ||
--- | ||
|
||
# netbox_virtual_chassis (Resource) | ||
|
||
From the [official documentation](https://docs.netbox.dev/en/stable/features/devices-cabling/#virtual-chassis): | ||
|
||
> Sometimes it is necessary to model a set of physical devices as sharing a single management plane. Perhaps the most common example of such a scenario is stackable switches. These can be modeled as virtual chassis in NetBox, with one device acting as the chassis master and the rest as members. All components of member devices will appear on the master. | ||
|
||
## Example Usage | ||
|
||
```terraform | ||
resource "netbox_virtual_chassis" "example" { | ||
name = "chassis" | ||
domain = "domain" | ||
description = "virtual chassis" | ||
} | ||
``` | ||
|
||
<!-- schema generated by tfplugindocs --> | ||
## Schema | ||
|
||
### Required | ||
|
||
- `name` (String) | ||
|
||
### Optional | ||
|
||
- `comments` (String) | ||
- `custom_fields` (Map of String) | ||
- `description` (String) | ||
- `domain` (String) | ||
- `tags` (Set of String) | ||
|
||
### Read-Only | ||
|
||
- `id` (String) The ID of this 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
resource "netbox_virtual_chassis" "example" { | ||
name = "chassis" | ||
domain = "domain" | ||
description = "virtual chassis" | ||
} |
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,198 @@ | ||
package netbox | ||
|
||
import ( | ||
"context" | ||
"strconv" | ||
|
||
"github.com/fbreckle/go-netbox/netbox/client" | ||
"github.com/fbreckle/go-netbox/netbox/client/dcim" | ||
"github.com/fbreckle/go-netbox/netbox/models" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" | ||
) | ||
|
||
func resourceNetboxVirtualChassis() *schema.Resource { | ||
return &schema.Resource{ | ||
CreateContext: resourceNetboxVirtualChassisCreate, | ||
ReadContext: resourceNetboxVirtualChassisRead, | ||
UpdateContext: resourceNetboxVirtualChassisUpdate, | ||
DeleteContext: resourceNetboxVirtualChassisDelete, | ||
Description: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/features/devices-cabling/#virtual-chassis): | ||
> Sometimes it is necessary to model a set of physical devices as sharing a single management plane. Perhaps the most common example of such a scenario is stackable switches. These can be modeled as virtual chassis in NetBox, with one device acting as the chassis master and the rest as members. All components of member devices will appear on the master.`, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"name": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
}, | ||
"domain": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
}, | ||
"description": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
}, | ||
"comments": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
}, | ||
tagsKey: tagsSchema, | ||
customFieldsKey: customFieldsSchema, | ||
}, | ||
Importer: &schema.ResourceImporter{ | ||
StateContext: schema.ImportStatePassthroughContext, | ||
}, | ||
} | ||
} | ||
|
||
func resourceNetboxVirtualChassisCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { | ||
api := m.(*client.NetBoxAPI) | ||
|
||
name := d.Get("name").(string) | ||
|
||
data := models.WritableVirtualChassis{ | ||
Name: &name, | ||
} | ||
|
||
domainValue, ok := d.GetOk("domain") | ||
if ok { | ||
domain := domainValue.(string) | ||
data.Domain = domain | ||
} | ||
|
||
descriptionValue, ok := d.GetOk("description") | ||
if ok { | ||
description := descriptionValue.(string) | ||
data.Description = description | ||
} | ||
|
||
commentsValue, ok := d.GetOk("comments") | ||
if ok { | ||
comments := commentsValue.(string) | ||
data.Comments = comments | ||
} | ||
|
||
ct, ok := d.GetOk(customFieldsKey) | ||
if ok { | ||
data.CustomFields = ct | ||
} | ||
|
||
data.Tags, _ = getNestedTagListFromResourceDataSet(api, d.Get(tagsKey)) | ||
|
||
params := dcim.NewDcimVirtualChassisCreateParams().WithData(&data) | ||
|
||
res, err := api.Dcim.DcimVirtualChassisCreate(params, nil) | ||
if err != nil { | ||
return diag.FromErr(err) | ||
} | ||
|
||
d.SetId(strconv.FormatInt(res.GetPayload().ID, 10)) | ||
|
||
return resourceNetboxVirtualChassisRead(ctx, d, m) | ||
} | ||
|
||
func resourceNetboxVirtualChassisRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { | ||
api := m.(*client.NetBoxAPI) | ||
|
||
id, _ := strconv.ParseInt(d.Id(), 10, 64) | ||
|
||
params := dcim.NewDcimVirtualChassisReadParams().WithID(id) | ||
|
||
res, err := api.Dcim.DcimVirtualChassisRead(params, nil) | ||
if err != nil { | ||
if errresp, ok := err.(*dcim.DcimVirtualChassisReadDefault); ok { | ||
errorcode := errresp.Code() | ||
if errorcode == 404 { | ||
d.SetId("") | ||
return nil | ||
} | ||
} | ||
return diag.FromErr(err) | ||
} | ||
|
||
virtualChassis := res.GetPayload() | ||
|
||
d.Set("name", virtualChassis.Name) | ||
d.Set("domain", virtualChassis.Domain) | ||
d.Set("description", virtualChassis.Description) | ||
d.Set("comments", virtualChassis.Comments) | ||
|
||
cf := getCustomFields(res.GetPayload().CustomFields) | ||
if cf != nil { | ||
d.Set(customFieldsKey, cf) | ||
} | ||
|
||
d.Set(tagsKey, getTagListFromNestedTagList(virtualChassis.Tags)) | ||
return nil | ||
} | ||
|
||
func resourceNetboxVirtualChassisUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { | ||
api := m.(*client.NetBoxAPI) | ||
|
||
id, _ := strconv.ParseInt(d.Id(), 10, 64) | ||
data := models.WritableVirtualChassis{} | ||
|
||
name := d.Get("name").(string) | ||
data.Name = &name | ||
|
||
domainValue, ok := d.GetOk("domain") | ||
if ok { | ||
domain := domainValue.(string) | ||
data.Domain = domain | ||
} | ||
|
||
ct, ok := d.GetOk(customFieldsKey) | ||
if ok { | ||
data.CustomFields = ct | ||
} | ||
|
||
data.Tags, _ = getNestedTagListFromResourceDataSet(api, d.Get(tagsKey)) | ||
|
||
if d.HasChanges("comments") { | ||
// check if comment is set | ||
if commentsValue, ok := d.GetOk("comments"); ok { | ||
data.Comments = commentsValue.(string) | ||
} else { | ||
data.Comments = " " | ||
} | ||
} | ||
if d.HasChanges("description") { | ||
// check if description is set | ||
if descriptionValue, ok := d.GetOk("description"); ok { | ||
data.Description = descriptionValue.(string) | ||
} else { | ||
data.Description = " " | ||
} | ||
} | ||
|
||
params := dcim.NewDcimVirtualChassisUpdateParams().WithID(id).WithData(&data) | ||
|
||
_, err := api.Dcim.DcimVirtualChassisUpdate(params, nil) | ||
if err != nil { | ||
return diag.FromErr(err) | ||
} | ||
|
||
return resourceNetboxVirtualChassisRead(ctx, d, m) | ||
} | ||
|
||
func resourceNetboxVirtualChassisDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { | ||
api := m.(*client.NetBoxAPI) | ||
|
||
id, _ := strconv.ParseInt(d.Id(), 10, 64) | ||
params := dcim.NewDcimVirtualChassisDeleteParams().WithID(id) | ||
|
||
_, err := api.Dcim.DcimVirtualChassisDelete(params, nil) | ||
if err != nil { | ||
if errresp, ok := err.(*dcim.DcimVirtualChassisDeleteDefault); ok { | ||
if errresp.Code() == 404 { | ||
d.SetId("") | ||
return nil | ||
} | ||
} | ||
return diag.FromErr(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,91 @@ | ||
package netbox | ||
|
||
import ( | ||
"fmt" | ||
"strconv" | ||
"testing" | ||
|
||
"github.com/fbreckle/go-netbox/netbox/client" | ||
"github.com/fbreckle/go-netbox/netbox/client/dcim" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform" | ||
) | ||
|
||
func TestAccNetboxVirtualChassis_basic(t *testing.T) { | ||
testSlug := "virtual_chassis" | ||
testName := testAccGetTestName(testSlug) | ||
|
||
resource.ParallelTest(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
CheckDestroy: testAccCheckVirtualChassisDestroy, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: fmt.Sprintf(` | ||
resource "netbox_tag" "tag_a" { | ||
name = "[%[1]s_a]" | ||
color_hex = "123456" | ||
} | ||
resource "netbox_virtual_chassis" "test" { | ||
name = "%[1]s" | ||
domain = "domain" | ||
description = "description" | ||
comments = "comment" | ||
tags = [netbox_tag.tag_a.name] | ||
} | ||
`, testName), | ||
}, | ||
{ | ||
Config: fmt.Sprintf(` | ||
resource "netbox_tag" "tag_a" { | ||
name = "[%[1]s_a]" | ||
color_hex = "123456" | ||
} | ||
resource "netbox_virtual_chassis" "test" { | ||
name = "%[1]s_updated" | ||
domain = "domain_updated" | ||
description = "description updated" | ||
comments = "comment updated" | ||
tags = [netbox_tag.tag_a.name] | ||
} | ||
`, testName), | ||
}, | ||
{ | ||
ResourceName: "netbox_virtual_chassis.test", | ||
ImportState: true, | ||
ImportStateVerify: true, | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccCheckVirtualChassisDestroy(s *terraform.State) error { | ||
conn := testAccProvider.Meta().(*client.NetBoxAPI) | ||
|
||
// loop through the resources in state, verifying each virtual machine | ||
// is destroyed | ||
for _, rs := range s.RootModule().Resources { | ||
if rs.Type != "netbox_virtual_chassis" { | ||
continue | ||
} | ||
|
||
stateID, _ := strconv.ParseInt(rs.Primary.ID, 10, 64) | ||
params := dcim.NewDcimVirtualChassisReadParams().WithID(stateID) | ||
_, err := conn.Dcim.DcimVirtualChassisRead(params, nil) | ||
|
||
if err == nil { | ||
return fmt.Errorf("virtual chassis (%s) still exists", rs.Primary.ID) | ||
} | ||
|
||
if err != nil { | ||
if errresp, ok := err.(*dcim.DcimVirtualChassisReadDefault); ok { | ||
errorcode := errresp.Code() | ||
if errorcode == 404 { | ||
return nil | ||
} | ||
} | ||
return err | ||
} | ||
} | ||
return nil | ||
} |