Skip to content

Commit

Permalink
feat: add locations data source
Browse files Browse the repository at this point in the history
Similar to the prefixes data source, this data source returns a list of
zero or more locations based on the provided filters. This allows you to
search for locations with certain criteria which may not exist.
  • Loading branch information
Ikke committed Nov 24, 2023
1 parent 3879a7d commit ec7ebaf
Show file tree
Hide file tree
Showing 4 changed files with 385 additions and 0 deletions.
51 changes: 51 additions & 0 deletions docs/data-sources/locations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
# generated by https://github.com/fbreckle/terraform-plugin-docs
page_title: "netbox_locations Data Source - terraform-provider-netbox"
subcategory: "Data Center Inventory Management (DCIM)"
description: |-
---

# netbox_locations (Data Source)





<!-- schema generated by tfplugindocs -->
## Schema

### Optional

- `filter` (Block Set) A list of filter to apply to the API query when requesting locations. (see [below for nested schema](#nestedblock--filter))
- `limit` (Number) The limit of objects to return from the API lookup. Defaults to `0`.
- `tags` (Set of String) A list of tags to filter on.

### Read-Only

- `id` (String) The ID of this resource.
- `locations` (List of Object) (see [below for nested schema](#nestedatt--locations))

<a id="nestedblock--filter"></a>
### Nested Schema for `filter`

Required:

- `name` (String) The name of the field to filter on. Supported fields are: .
- `value` (String) The value to pass to the specified filter.


<a id="nestedatt--locations"></a>
### Nested Schema for `locations`

Read-Only:

- `description` (String)
- `id` (String)
- `name` (String)
- `site_id` (Number)
- `slug` (String)
- `status` (String)
- `tenant_id` (Number)


165 changes: 165 additions & 0 deletions netbox/data_source_netbox_locations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package netbox

import (
"fmt"
"strconv"

"github.com/fbreckle/go-netbox/netbox/client"
"github.com/fbreckle/go-netbox/netbox/client/dcim"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/id"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)

func dataSourceNetboxLocations() *schema.Resource {
return &schema.Resource{
Read: dataSourceNetboxLocationsRead,
Description: `:meta:subcategory:Data Center Inventory Management (DCIM):`,
Schema: map[string]*schema.Schema{
"filter": {
Type: schema.TypeSet,
Optional: true,
Description: "A list of filter to apply to the API query when requesting locations.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
Description: "The name of the field to filter on. Supported fields are: .",
},
"value": {
Type: schema.TypeString,
Required: true,
Description: "The value to pass to the specified filter.",
},
},
},
},
"tags": {
Type: schema.TypeSet,
Elem: &schema.Schema{
Type: schema.TypeString,
},
Optional: true,
Description: "A list of tags to filter on.",
},
"limit": {
Type: schema.TypeInt,
Optional: true,
ValidateDiagFunc: validation.ToDiagFunc(validation.IntAtLeast(1)),
Default: 0,
Description: "The limit of objects to return from the API lookup.",
},
"locations": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"id": {
Type: schema.TypeString,
Computed: true,
},
"name": {
Type: schema.TypeString,
Optional: true,
},
"slug": {
Type: schema.TypeString,
Optional: true,
},
"description": {
Type: schema.TypeString,
Computed: true,
},
"tenant_id": {
Type: schema.TypeInt,
Computed: true,
},
"status": {
Type: schema.TypeString,
Computed: true,
},
"site_id": {
Type: schema.TypeInt,
Computed: true,
},
},
},
},
},
}
}

func dataSourceNetboxLocationsRead(d *schema.ResourceData, m interface{}) error {
api := m.(*client.NetBoxAPI)
params := dcim.NewDcimLocationsListParams()

if limitValue, ok := d.GetOk("limit"); ok {
params.Limit = int64ToPtr(int64(limitValue.(int)))
}

if filter, ok := d.GetOk("filter"); ok {
var filterParams = filter.(*schema.Set)
for _, f := range filterParams.List() {
k := f.(map[string]interface{})["name"]
v := f.(map[string]interface{})["value"]
vString := v.(string)
switch k {
case "name":
params.Name = &vString
case "slug":
params.Slug = &vString
case "site":
params.Site = &vString
case "site_id":
params.SiteID = &vString
case "tenant":
params.Tenant = &vString
case "tenant_id":
params.TenantID = &vString
case "status":
params.Status = &vString
default:
return fmt.Errorf("'%s' is not a supported filter parameter", k)
}
}
}
if tags, ok := d.GetOk("tags"); ok {
tagSet := tags.(*schema.Set)
for _, tag := range tagSet.List() {
tagV := tag.(string)
params.Tag = append(params.Tag, tagV)
}
}
res, err := api.Dcim.DcimLocationsList(params, nil)

if err != nil {
return err
}

filteredLocations := res.GetPayload().Results

var s []map[string]any
for _, v := range filteredLocations {
var mapping = make(map[string]any)

mapping["id"] = strconv.FormatInt(v.ID, 10)
mapping["name"] = v.Name
mapping["slug"] = v.Slug
mapping["site_id"] = v.Site.ID
mapping["description"] = v.Description

if v.Status != nil {
mapping["status"] = v.Status.Value
}

if v.Tenant != nil {
mapping["tenant_id"] = v.Tenant.ID
}

s = append(s, mapping)
}

d.SetId(id.UniqueId())
return d.Set("locations", s)
}
168 changes: 168 additions & 0 deletions netbox/data_source_netbox_locations_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
package netbox

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestAccNetboxLocationsDataSource_basic(t *testing.T) {
testSlug := "location_ds_basic"
testName := testAccGetTestName(testSlug)
resource.ParallelTest(t, resource.TestCase{
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(`
resource "netbox_site" "test" {
name = "%[1]s"
}
resource "netbox_tenant" "test" {
name = "%[1]s"
}
resource "netbox_tag" "test" {
name = "%[1]s"
}
resource "netbox_location" "test" {
name = "%[1]s"
description = "my-description"
site_id = netbox_site.test.id
tenant_id = netbox_tenant.test.id
tags = [netbox_tag.test.slug]
}
data "netbox_locations" "by_name" {
filter {
name = "name"
value = netbox_location.test.name
}
}
data "netbox_locations" "no_match" {
filter {
name = "name"
value = "non-existent"
}
}
data "netbox_locations" "by_site_slug" {
filter {
name = "site"
value = netbox_site.test.slug
}
depends_on = [netbox_location.test]
}
data "netbox_locations" "by_site_id" {
filter {
name = "site_id"
value = netbox_site.test.id
}
depends_on = [netbox_location.test]
}
data "netbox_locations" "by_tenant_slug" {
filter {
name = "tenant"
value = netbox_tenant.test.slug
}
depends_on = [netbox_location.test]
}
data "netbox_locations" "by_tenant_id" {
filter {
name = "tenant_id"
value = netbox_tenant.test.id
}
depends_on = [netbox_location.test]
}
data "netbox_locations" "by_tags" {
tags = [netbox_tag.test.slug]
depends_on = [netbox_location.test]
}`, testName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.netbox_locations.by_name", "locations.#", "1"),
resource.TestCheckResourceAttrPair("data.netbox_locations.by_name", "locations.0.name", "netbox_location.test", "name"),
resource.TestCheckResourceAttrPair("data.netbox_locations.by_name", "locations.0.site_id", "netbox_site.test", "id"),
resource.TestCheckResourceAttrPair("data.netbox_locations.by_name", "locations.0.tenant_id", "netbox_tenant.test", "id"),
resource.TestCheckResourceAttr("data.netbox_locations.by_name", "locations.0.description", "my-description"),
resource.TestCheckResourceAttr("data.netbox_locations.no_match", "locations.#", "0"),
resource.TestCheckResourceAttr("data.netbox_locations.by_site_slug", "locations.#", "1"),
resource.TestCheckResourceAttrPair("data.netbox_locations.by_site_slug", "locations.0.name", "netbox_location.test", "name"),
resource.TestCheckResourceAttr("data.netbox_locations.by_site_id", "locations.#", "1"),
resource.TestCheckResourceAttrPair("data.netbox_locations.by_site_id", "locations.0.name", "netbox_location.test", "name"),
resource.TestCheckResourceAttr("data.netbox_locations.by_tenant_slug", "locations.#", "1"),
resource.TestCheckResourceAttrPair("data.netbox_locations.by_tenant_slug", "locations.0.name", "netbox_location.test", "name"),
resource.TestCheckResourceAttr("data.netbox_locations.by_tenant_id", "locations.#", "1"),
resource.TestCheckResourceAttrPair("data.netbox_locations.by_tenant_id", "locations.0.name", "netbox_location.test", "name"),
resource.TestCheckResourceAttr("data.netbox_locations.by_tags", "locations.#", "1"),
resource.TestCheckResourceAttrPair("data.netbox_locations.by_tags", "locations.0.name", "netbox_location.test", "name"),
),
},
},
})
}

func TestAccNetboxLocationsDataSource_multiple(t *testing.T) {
testSlug := "location_ds_multiple"
testName := testAccGetTestName(testSlug)
resource.ParallelTest(t, resource.TestCase{
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(`
resource "netbox_site" "test" {
name = "%[1]s"
}
resource "netbox_tenant" "test" {
name = "%[1]s"
}
resource "netbox_tag" "test1" {
name = "%[1]s_1"
}
resource "netbox_tag" "test2" {
name = "%[1]s_2"
}
resource "netbox_location" "test1" {
name = "%[1]s_1"
site_id = netbox_site.test.id
tenant_id = netbox_tenant.test.id
tags = [netbox_tag.test1.slug]
}
resource "netbox_location" "test2" {
name = "%[1]s_2"
site_id = netbox_site.test.id
tenant_id = netbox_tenant.test.id
tags = [netbox_tag.test2.slug]
}
data "netbox_locations" "by_site" {
filter {
name = "site"
value = netbox_site.test.name
}
depends_on = [netbox_location.test1, netbox_location.test2]
}
data "netbox_locations" "by_tag" {
tags = [netbox_tag.test1.slug]
depends_on = [netbox_location.test1, netbox_location.test2]
}`, testName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.netbox_locations.by_site", "locations.#", "2"),
resource.TestCheckResourceAttr("data.netbox_locations.by_tag", "locations.#", "1"),
),
},
},
})
}
1 change: 1 addition & 0 deletions netbox/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ func Provider() *schema.Provider {
"netbox_device_type": dataSourceNetboxDeviceType(),
"netbox_site": dataSourceNetboxSite(),
"netbox_location": dataSourceNetboxLocation(),
"netbox_locations": dataSourceNetboxLocations(),
"netbox_tag": dataSourceNetboxTag(),
"netbox_tags": dataSourceNetboxTags(),
"netbox_virtual_machines": dataSourceNetboxVirtualMachine(),
Expand Down

0 comments on commit ec7ebaf

Please sign in to comment.