diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml
index 65da16a4..0fbab038 100644
--- a/.github/workflows/ci-testing.yml
+++ b/.github/workflows/ci-testing.yml
@@ -8,7 +8,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v3
with:
- go-version: 1.18
+ go-version: 1.19
- uses: actions/cache@v3
with:
path: |
@@ -25,6 +25,9 @@ jobs:
strategy:
matrix:
netbox-version:
+ - "v3.3.7"
+ - "v3.3.6"
+ - "v3.3.5"
- "v3.3.4"
- "v3.3.3"
- "v3.3.2"
@@ -34,7 +37,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v3
with:
- go-version: 1.18
+ go-version: 1.19
- uses: actions/cache@v3
with:
path: |
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 4a66275c..ab8cbe05 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -25,7 +25,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v3
with:
- go-version: 1.18
+ go-version: 1.19
- name: Import GPG key
id: import_gpg
uses: paultyng/ghaction-import-gpg@v2.1.0
@@ -33,7 +33,7 @@ jobs:
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
PASSPHRASE: ${{ secrets.PASSPHRASE }}
- name: Run GoReleaser
- uses: goreleaser/goreleaser-action@v3.1.0
+ uses: goreleaser/goreleaser-action@v3.2.0
with:
version: latest
args: release --rm-dist
diff --git a/.gitignore b/.gitignore
index 3eef5b1d..1b9cba81 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
*.dll
*.exe
+.envrc
.DS_Store
example.tf
terraform.tfplan
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f2c1fbc6..1758f227 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,69 @@
+## 3.0.8 (November 9th, 2022)
+
+ENHANCEMENTS
+
+* **New Resource:** `netbox_device_interface` ([#286](https://github.com/e-breuninger/terraform-provider-netbox/pull/286) by [@arjenvri](https://github.com/arjenvri))
+* **New Data Source:** `netbox_asn` ([#285](https://github.com/e-breuninger/terraform-provider-netbox/pull/285) by [@kyle-burnett](https://github.com/kyle-burnett))
+* **New Data Source:** `netbox_asns` ([#292](https://github.com/e-breuninger/terraform-provider-netbox/pull/292) by [@kyle-burnett](https://github.com/kyle-burnett))
+* data-source/netbox_prefix: Add `tags` and tag filter attributes ([#284](https://github.com/e-breuninger/terraform-provider-netbox/pull/284) by [@kyle-burnett](https://github.com/kyle-burnett))
+
+BUG FIXES
+* data-source/netbox_prefixes: FIx kernel panic when finding prefixes without vlan or vrf
+
+## 3.0.7 (November 3rd, 2022)
+
+ENHANCEMENTS
+
+* **New Resource:** `netbox_contact_role` ([#279](https://github.com/e-breuninger/terraform-provider-netbox/pull/279) by [@arjenvri](https://github.com/arjenvri))
+* **New Resource:** `netbox_contact_assignment` ([#279](https://github.com/e-breuninger/terraform-provider-netbox/pull/279) by [@arjenvri](https://github.com/arjenvri))
+* resource/netbox_device: Add `primary_ipv6` attribute ([#282](https://github.com/e-breuninger/terraform-provider-netbox/pull/282) by [@arjenvri](https://github.com/arjenvri))
+* resource/netbox_virtual_machine: Add `primary_ipv6` attribute ([#283](https://github.com/e-breuninger/terraform-provider-netbox/pull/283) by [@arjenvri](https://github.com/arjenvri))
+* resource/netbox_custom_field: Add `group_name` atribute ([#280](https://github.com/e-breuninger/terraform-provider-netbox/pull/280) by [@arjenvri](https://github.com/arjenvri))
+
+## 3.0.6 (October 21st, 2022)
+
+ENHANCEMENTS
+
+* **New Resource:** `netbox_contact` ([#273](https://github.com/e-breuninger/terraform-provider-netbox/pull/273) by [@arjenvri](https://github.com/arjenvri))
+* data-source/netbox_prefix: Add `description` attribute ([#277](https://github.com/e-breuninger/terraform-provider-netbox/pull/277) by [@holmesb](https://github.com/holmesb))
+* resource/netbox_cluster: Add `tenant_id` attribute ([#275](https://github.com/e-breuninger/terraform-provider-netbox/pull/275) by [@arjenvri](https://github.com/arjenvri))
+
+## 3.0.5 (October 18th, 2022)
+
+ENHANCEMENTS
+
+* resource/netbox_device_role: Add `tags` attribute ([#269](https://github.com/e-breuninger/terraform-provider-netbox/pull/269) by [@hollow](https://github.com/hollow))
+* data-source/netbox_device_role: Add `tags` attribute ([#269](https://github.com/e-breuninger/terraform-provider-netbox/pull/269) by [@hollow](https://github.com/hollow))
+
+CHANGES
+
+* resource/netbox_service: Implement provider-side validation on allowed values. Valid values are `tcp`, `udp` and `sctp`.
+
+## 3.0.4 (October 11th, 2022)
+
+ENHANCEMENTS
+
+* resource/netbox_device: Add `platform_id` attribute ([#264](https://github.com/e-breuninger/terraform-provider-netbox/pull/264) by [@mifrost](https://github.com/mifrost))
+* **New Data Source:** `netbox_prefixes ` ([#253](https://github.com/e-breuninger/terraform-provider-netbox/pull/253) by [@ironashram](https://github.com/ironashram))
+* data-source/netbox_prefix: Add `prefix`, `status`, `vlan_id`, `vlan_vid` attributes ([#253](https://github.com/e-breuninger/terraform-provider-netbox/pull/253) by [@ironashram](https://github.com/ironashram))
+* resource/netbox_device: Add `status` attribute [#266](https://github.com/e-breuninger/terraform-provider-netbox/pull/266) by [@mifrost](https://github.com/mifrost))
+
+CHANGES
+
+* resource/netbox_prefix: Deprecate `cidr` attribute in favor of new canonical `prefix` attribute
+
+## 3.0.3 (October 4th, 2022)
+
+ENHANCEMENTS
+
+* resource/netbox_site: Add `group_id` attribute ([#255](https://github.com/e-breuninger/terraform-provider-netbox/pull/255) by [@arjenvri](https://github.com/arjenvri))
+
+## 3.0.2 (September 30th, 2022)
+
+ENHANCEMENTS
+
+* data-source/netbox_cluster: Add `site_id`, `cluster_type_id`, `cluster_group_id` and `tags` attribute ([#251](https://github.com/e-breuninger/terraform-provider-netbox/pull/251) by [@ns1pelle](https://github.com/ns1pelle))
+
## 3.0.1 (September 25th, 2022)
This is a re-release of 3.0.0 because there seem to be some issues with the checksums in the 3.0.0 version.
@@ -22,7 +88,7 @@ ENHANCEMENTS
* **New Data Source:** `netbox_devices` ([#236](https://github.com/e-breuninger/terraform-provider-netbox/pull/236) by [@dipeshsharma](https://github.com/dipeshsharma))
* provider: Add `request_timeout` attribute ([#227](https://github.com/e-breuninger/terraform-provider-netbox/pull/227) by [@twink0r](https://github.com/twink0r))
-* data-source/netbox-tenants: Added `limit` attribute to allow for larger queries
+* data-source/netbox_tenants: Add `limit` attribute to allow for larger queries
## 2.0.6 (September 9th, 2022)
diff --git a/GNUmakefile b/GNUmakefile
index 74118810..90075321 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -2,7 +2,7 @@ TEST?=netbox/*.go
GOFMT_FILES?=$$(find . -name '*.go' |grep -v vendor)
DOCKER_COMPOSE=docker-compose
-export NETBOX_VERSION=v3.3.4
+export NETBOX_VERSION=v3.3.7
export NETBOX_SERVER_URL=http://localhost:8001
export NETBOX_API_TOKEN=0123456789abcdef0123456789abcdef01234567
export NETBOX_TOKEN=$(NETBOX_API_TOKEN)
diff --git a/docs/data-sources/asn.md b/docs/data-sources/asn.md
new file mode 100644
index 00000000..af829796
--- /dev/null
+++ b/docs/data-sources/asn.md
@@ -0,0 +1,44 @@
+---
+# generated by https://github.com/fbreckle/terraform-plugin-docs
+page_title: "netbox_asn Data Source - terraform-provider-netbox"
+subcategory: "IP Address Management (IPAM)"
+description: |-
+
+---
+
+# netbox_asn (Data Source)
+
+
+
+## Example Usage
+
+```terraform
+data "netbox_asn" "asn_1" {
+ asn = "1111"
+ tag = "tag-1"
+}
+
+data "netbox_asn" "asn_2" {
+ tag = "tag-1"
+ tag__n = "tag-2"
+}
+```
+
+
+## Schema
+
+### Optional
+
+- `asn` (String) At least one of `asn` or `tag` must be given.
+- `tag` (String) Tag to include in the data source filter (must match the tag's slug). At least one of `asn` or `tag` must be given.
+- `tag__n` (String) Tag to exclude from the data source filter (must match the tag's slug).
+Refer to [Netbox's documentation](https://demo.netbox.dev/static/docs/rest-api/filtering/#lookup-expressions)
+for more information on available lookup expressions.
+
+### Read-Only
+
+- `description` (String)
+- `id` (Number) The ID of this resource.
+- `tags` (Set of String)
+
+
diff --git a/docs/data-sources/asns.md b/docs/data-sources/asns.md
new file mode 100644
index 00000000..e3ea0a65
--- /dev/null
+++ b/docs/data-sources/asns.md
@@ -0,0 +1,60 @@
+---
+# generated by https://github.com/fbreckle/terraform-plugin-docs
+page_title: "netbox_asns Data Source - terraform-provider-netbox"
+subcategory: "IP Address Management (IPAM)"
+description: |-
+
+---
+
+# netbox_asns (Data Source)
+
+
+
+## Example Usage
+
+```terraform
+data "netbox_asns" "asns" {
+ filter {
+ name = "asn__gte"
+ value = "1000"
+ }
+ filter {
+ name = "asn__lte"
+ value = "2000"
+ }
+}
+```
+
+
+## Schema
+
+### Optional
+
+- `filter` (Block Set) (see [below for nested schema](#nestedblock--filter))
+- `limit` (Number) Defaults to `0`.
+
+### Read-Only
+
+- `asns` (List of Object) (see [below for nested schema](#nestedatt--asns))
+- `id` (String) The ID of this resource.
+
+
+### Nested Schema for `filter`
+
+Required:
+
+- `name` (String)
+- `value` (String)
+
+
+
+### Nested Schema for `asns`
+
+Read-Only:
+
+- `asn` (Number)
+- `id` (Number)
+- `rir_id` (Number)
+- `tags` (Set of String)
+
+
diff --git a/docs/data-sources/cluster.md b/docs/data-sources/cluster.md
index 5930a805..ec4cdd6c 100644
--- a/docs/data-sources/cluster.md
+++ b/docs/data-sources/cluster.md
@@ -27,7 +27,11 @@ data "netbox_cluster" "vmw_cluster_01" {
### Read-Only
+- `cluster_group_id` (Number)
- `cluster_id` (Number)
+- `cluster_type_id` (Number)
- `id` (String) The ID of this resource.
+- `site_id` (Number)
+- `tags` (Set of String)
diff --git a/docs/data-sources/device_role.md b/docs/data-sources/device_role.md
index a944e8ee..efec39fc 100644
--- a/docs/data-sources/device_role.md
+++ b/docs/data-sources/device_role.md
@@ -30,5 +30,6 @@ data "netbox_device_role" "core_sw" {
- `color_hex` (String)
- `id` (String) The ID of this resource.
- `slug` (String)
+- `tags` (Set of String)
diff --git a/docs/data-sources/prefix.md b/docs/data-sources/prefix.md
index 72af8f9f..e806a0ac 100644
--- a/docs/data-sources/prefix.md
+++ b/docs/data-sources/prefix.md
@@ -17,11 +17,21 @@ description: |-
### Optional
-- `cidr` (String)
-- `vrf_id` (Number)
+- `cidr` (String, Deprecated) At least one of `description`, `prefix`, `vlan_vid`, `vrf_id`, `vlan_id`, `cidr` or `tag` must be given. Conflicts with `prefix`.
+- `description` (String) Description to include in the data source filter. At least one of `description`, `prefix`, `vlan_vid`, `vrf_id`, `vlan_id`, `cidr` or `tag` must be given.
+- `prefix` (String) At least one of `description`, `prefix`, `vlan_vid`, `vrf_id`, `vlan_id`, `cidr` or `tag` must be given. Conflicts with `cidr`.
+- `tag` (String) Tag to include in the data source filter (must match the tag's slug). At least one of `description`, `prefix`, `vlan_vid`, `vrf_id`, `vlan_id`, `cidr` or `tag` must be given.
+- `tag__n` (String) Tag to exclude from the data source filter (must match the tag's slug).
+Refer to [Netbox's documentation](https://demo.netbox.dev/static/docs/rest-api/filtering/#lookup-expressions)
+for more information on available lookup expressions.
+- `vlan_id` (Number) At least one of `description`, `prefix`, `vlan_vid`, `vrf_id`, `vlan_id`, `cidr` or `tag` must be given.
+- `vlan_vid` (Number) At least one of `description`, `prefix`, `vlan_vid`, `vrf_id`, `vlan_id`, `cidr` or `tag` must be given.
+- `vrf_id` (Number) At least one of `description`, `prefix`, `vlan_vid`, `vrf_id`, `vlan_id`, `cidr` or `tag` must be given.
### Read-Only
- `id` (Number) The ID of this resource.
+- `status` (String)
+- `tags` (Set of String)
diff --git a/docs/data-sources/prefixes.md b/docs/data-sources/prefixes.md
new file mode 100644
index 00000000..542dc7b6
--- /dev/null
+++ b/docs/data-sources/prefixes.md
@@ -0,0 +1,49 @@
+---
+# generated by https://github.com/fbreckle/terraform-plugin-docs
+page_title: "netbox_prefixes Data Source - terraform-provider-netbox"
+subcategory: "IP Address Management (IPAM)"
+description: |-
+
+---
+
+# netbox_prefixes (Data Source)
+
+
+
+
+
+
+## Schema
+
+### Optional
+
+- `filter` (Block Set) (see [below for nested schema](#nestedblock--filter))
+- `limit` (Number) Defaults to `0`.
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+- `prefixes` (List of Object) (see [below for nested schema](#nestedatt--prefixes))
+
+
+### Nested Schema for `filter`
+
+Required:
+
+- `name` (String)
+- `value` (String)
+
+
+
+### Nested Schema for `prefixes`
+
+Read-Only:
+
+- `id` (Number)
+- `prefix` (String)
+- `status` (String)
+- `vlan_id` (Number)
+- `vlan_vid` (Number)
+- `vrf_id` (Number)
+
+
diff --git a/docs/data-sources/tenant.md b/docs/data-sources/tenant.md
index e45f315e..e173fcd8 100644
--- a/docs/data-sources/tenant.md
+++ b/docs/data-sources/tenant.md
@@ -23,6 +23,7 @@ data "netbox_tenant" "customer_a" {
### Optional
+- `description` (String)
- `name` (String) At least one of `name` or `slug` must be given.
- `slug` (String) At least one of `name` or `slug` must be given.
diff --git a/docs/data-sources/vlan.md b/docs/data-sources/vlan.md
index 5d372efc..8b0ce19b 100644
--- a/docs/data-sources/vlan.md
+++ b/docs/data-sources/vlan.md
@@ -18,9 +18,16 @@ data "netbox_vlan" "vlan1" {
name = "vlan-1"
}
-# Get VLAN by VLAN ID
+# Get VLAN by VID and IPAM role ID
data "netbox_vlan" "vlan2" {
- vid = 1234
+ vid = 1234
+ role = netbox_ipam_role.example.id
+}
+
+# Get VLAN by name and tenant ID
+data "netbox_vlan" "vlan3" {
+ name = "vlan-3"
+ tenant = netbox_tenant.example.id
}
```
@@ -29,16 +36,17 @@ data "netbox_vlan" "vlan2" {
### Optional
-- `name` (String) At least one of `name` or `vid` must be given.
-- `vid` (Number) At least one of `name` or `vid` must be given.
+- `group_id` (Number)
+- `name` (String)
+- `role` (Number)
+- `tenant` (Number)
+- `vid` (Number)
### Read-Only
- `description` (String)
- `id` (String) The ID of this resource.
-- `role` (Number)
- `site` (Number)
- `status` (String)
-- `tenant` (Number)
diff --git a/docs/index.md b/docs/index.md
index 772033b3..8346cc90 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -16,6 +16,7 @@ Netbox often makes breaking API changes even in non-major releases. Check the ta
Provider version | Netbox version
--- | ---
+v3.0.x | v3.3.0 and up
v2.0.x | v3.2.0 and up
v1.6.x and up| v3.1.9
v1.1.x and up | v3.1.3
diff --git a/docs/resources/aggregate.md b/docs/resources/aggregate.md
index b609306f..8a20a44b 100644
--- a/docs/resources/aggregate.md
+++ b/docs/resources/aggregate.md
@@ -3,13 +3,13 @@
page_title: "netbox_aggregate Resource - terraform-provider-netbox"
subcategory: "IP Address Management (IPAM)"
description: |-
- From the official documentation https://docs.netbox.dev/en/stable/core-functionality/ipam/#aggregates:
+ From the official documentation https://docs.netbox.dev/en/stable/features/ipam/#aggregates:
NetBox allows us to specify the portions of IP space that are interesting to us by defining aggregates. Typically, an aggregate will correspond to either an allocation of public (globally routable) IP space granted by a regional authority, or a private (internally-routable) designation.
---
# netbox_aggregate (Resource)
-From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/ipam/#aggregates):
+From the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#aggregates):
> NetBox allows us to specify the portions of IP space that are interesting to us by defining aggregates. Typically, an aggregate will correspond to either an allocation of public (globally routable) IP space granted by a regional authority, or a private (internally-routable) designation.
diff --git a/docs/resources/asn.md b/docs/resources/asn.md
index c96aa715..598d42ca 100644
--- a/docs/resources/asn.md
+++ b/docs/resources/asn.md
@@ -3,7 +3,7 @@
page_title: "netbox_asn Resource - terraform-provider-netbox"
subcategory: "IP Address Management (IPAM)"
description: |-
- From the official documentation https://docs.netbox.dev/en/stable/core-functionality/ipam/#asn:
+ From the official documentation https://docs.netbox.dev/en/stable/features/ipam/#asn:
> ASN is short for Autonomous System Number. This identifier is used in the BGP protocol to identify which "autonomous system" a particular prefix is originating and transiting through.
>
> The AS number model within NetBox allows you to model some of this real-world relationship.
@@ -11,7 +11,7 @@ description: |-
# netbox_asn (Resource)
-From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/ipam/#asn):
+From the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#asn):
> ASN is short for Autonomous System Number. This identifier is used in the BGP protocol to identify which "autonomous system" a particular prefix is originating and transiting through.
>
> The AS number model within NetBox allows you to model some of this real-world relationship.
diff --git a/docs/resources/circuit.md b/docs/resources/circuit.md
index c215aa78..248e3e02 100644
--- a/docs/resources/circuit.md
+++ b/docs/resources/circuit.md
@@ -3,14 +3,14 @@
page_title: "netbox_circuit Resource - terraform-provider-netbox"
subcategory: "Circuits"
description: |-
- From the official documentation https://docs.netbox.dev/en/stable/core-functionality/circuits/#circuits_1:
+ From the official documentation https://docs.netbox.dev/en/stable/features/circuits/#circuits_1:
A communications circuit represents a single physical link connecting exactly two endpoints, commonly referred to as its A and Z terminations. A circuit in NetBox may have zero, one, or two terminations defined. It is common to have only one termination defined when you don't necessarily care about the details of the provider side of the circuit, e.g. for Internet access circuits. Both terminations would likely be modeled for circuits which connect one customer site to another.
Each circuit is associated with a provider and a user-defined type. For example, you might have Internet access circuits delivered to each site by one provider, and private MPLS circuits delivered by another. Each circuit must be assigned a circuit ID, each of which must be unique per provider.
---
# netbox_circuit (Resource)
-From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/circuits/#circuits_1):
+From the [official documentation](https://docs.netbox.dev/en/stable/features/circuits/#circuits_1):
> A communications circuit represents a single physical link connecting exactly two endpoints, commonly referred to as its A and Z terminations. A circuit in NetBox may have zero, one, or two terminations defined. It is common to have only one termination defined when you don't necessarily care about the details of the provider side of the circuit, e.g. for Internet access circuits. Both terminations would likely be modeled for circuits which connect one customer site to another.
>
diff --git a/docs/resources/circuit_provider.md b/docs/resources/circuit_provider.md
index e3085c8d..5c6a1598 100644
--- a/docs/resources/circuit_provider.md
+++ b/docs/resources/circuit_provider.md
@@ -3,14 +3,14 @@
page_title: "netbox_circuit_provider Resource - terraform-provider-netbox"
subcategory: "Circuits"
description: |-
- From the official documentation https://docs.netbox.dev/en/stable/core-functionality/circuits/#providers:
+ From the official documentation https://docs.netbox.dev/en/stable/features/circuits/#providers:
A circuit provider is any entity which provides some form of connectivity of among sites or organizations within a site. While this obviously includes carriers which offer Internet and private transit service, it might also include Internet exchange (IX) points and even organizations with whom you peer directly. Each circuit within NetBox must be assigned a provider and a circuit ID which is unique to that provider.
Each provider may be assigned an autonomous system number (ASN), an account number, and contact information.
---
# netbox_circuit_provider (Resource)
-From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/circuits/#providers):
+From the [official documentation](https://docs.netbox.dev/en/stable/features/circuits/#providers):
> A circuit provider is any entity which provides some form of connectivity of among sites or organizations within a site. While this obviously includes carriers which offer Internet and private transit service, it might also include Internet exchange (IX) points and even organizations with whom you peer directly. Each circuit within NetBox must be assigned a provider and a circuit ID which is unique to that provider.
>
diff --git a/docs/resources/circuit_termination.md b/docs/resources/circuit_termination.md
index 6b684b83..826df834 100644
--- a/docs/resources/circuit_termination.md
+++ b/docs/resources/circuit_termination.md
@@ -3,14 +3,14 @@
page_title: "netbox_circuit_termination Resource - terraform-provider-netbox"
subcategory: "Circuits"
description: |-
- From the official documentation https://docs.netbox.dev/en/stable/core-functionality/circuits/#circuit-terminations:
+ From the official documentation https://docs.netbox.dev/en/stable/features/circuits/#circuit-terminations:
The association of a circuit with a particular site and/or device is modeled separately as a circuit termination. A circuit may have up to two terminations, labeled A and Z. A single-termination circuit can be used when you don't know (or care) about the far end of a circuit (for example, an Internet access circuit which connects to a transit provider). A dual-termination circuit is useful for tracking circuits which connect two sites.
Each circuit termination is attached to either a site or to a provider network. Site terminations may optionally be connected via a cable to a specific device interface or port within that site. Each termination must be assigned a port speed, and can optionally be assigned an upstream speed if it differs from the downstream speed (a common scenario with e.g. DOCSIS cable modems). Fields are also available to track cross-connect and patch panel details.
---
# netbox_circuit_termination (Resource)
-From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/circuits/#circuit-terminations):
+From the [official documentation](https://docs.netbox.dev/en/stable/features/circuits/#circuit-terminations):
> The association of a circuit with a particular site and/or device is modeled separately as a circuit termination. A circuit may have up to two terminations, labeled A and Z. A single-termination circuit can be used when you don't know (or care) about the far end of a circuit (for example, an Internet access circuit which connects to a transit provider). A dual-termination circuit is useful for tracking circuits which connect two sites.
>
diff --git a/docs/resources/circuit_type.md b/docs/resources/circuit_type.md
index 7bb2525f..f3a65541 100644
--- a/docs/resources/circuit_type.md
+++ b/docs/resources/circuit_type.md
@@ -3,13 +3,13 @@
page_title: "netbox_circuit_type Resource - terraform-provider-netbox"
subcategory: "Circuits"
description: |-
- From the official documentation https://docs.netbox.dev/en/stable/core-functionality/circuits/#circuit-types:
+ From the official documentation https://docs.netbox.dev/en/stable/features/circuits/#circuit-types:
Circuits are classified by functional type. These types are completely customizable, and are typically used to convey the type of service being delivered over a circuit.
---
# netbox_circuit_type (Resource)
-From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/circuits/#circuit-types):
+From the [official documentation](https://docs.netbox.dev/en/stable/features/circuits/#circuit-types):
> Circuits are classified by functional type. These types are completely customizable, and are typically used to convey the type of service being delivered over a circuit.
diff --git a/docs/resources/cluster.md b/docs/resources/cluster.md
index 73ed2973..9392d2ad 100644
--- a/docs/resources/cluster.md
+++ b/docs/resources/cluster.md
@@ -3,14 +3,14 @@
page_title: "netbox_cluster Resource - terraform-provider-netbox"
subcategory: "Virtualization"
description: |-
- From the official documentation https://docs.netbox.dev/en/stable/core-functionality/virtualization/#clusters:
+ From the official documentation https://docs.netbox.dev/en/stable/features/virtualization/#clusters:
A cluster is a logical grouping of physical resources within which virtual machines run. A cluster must be assigned a type (technological classification), and may optionally be assigned to a cluster group, site, and/or tenant. Each cluster must have a unique name within its assigned group and/or site, if any.
Physical devices may be associated with clusters as hosts. This allows users to track on which host(s) a particular virtual machine may reside. However, NetBox does not support pinning a specific VM within a cluster to a particular host device.
---
# netbox_cluster (Resource)
-From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/virtualization/#clusters):
+From the [official documentation](https://docs.netbox.dev/en/stable/features/virtualization/#clusters):
> A cluster is a logical grouping of physical resources within which virtual machines run. A cluster must be assigned a type (technological classification), and may optionally be assigned to a cluster group, site, and/or tenant. Each cluster must have a unique name within its assigned group and/or site, if any.
>
@@ -48,6 +48,7 @@ resource "netbox_cluster" "vmw_cluster_01" {
- `cluster_group_id` (Number)
- `site_id` (Number)
- `tags` (Set of String)
+- `tenant_id` (Number)
### Read-Only
diff --git a/docs/resources/cluster_group.md b/docs/resources/cluster_group.md
index 086c2d72..718903a6 100644
--- a/docs/resources/cluster_group.md
+++ b/docs/resources/cluster_group.md
@@ -3,13 +3,13 @@
page_title: "netbox_cluster_group Resource - terraform-provider-netbox"
subcategory: "Virtualization"
description: |-
- From the official documentation https://docs.netbox.dev/en/stable/core-functionality/virtualization/#cluster-groups:
+ From the official documentation https://docs.netbox.dev/en/stable/features/virtualization/#cluster-groups:
Cluster groups may be created for the purpose of organizing clusters. The arrangement of clusters into groups is optional.
---
# netbox_cluster_group (Resource)
-From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/virtualization/#cluster-groups):
+From the [official documentation](https://docs.netbox.dev/en/stable/features/virtualization/#cluster-groups):
> Cluster groups may be created for the purpose of organizing clusters. The arrangement of clusters into groups is optional.
diff --git a/docs/resources/cluster_type.md b/docs/resources/cluster_type.md
index 3063673f..abd0d56d 100644
--- a/docs/resources/cluster_type.md
+++ b/docs/resources/cluster_type.md
@@ -3,13 +3,13 @@
page_title: "netbox_cluster_type Resource - terraform-provider-netbox"
subcategory: "Virtualization"
description: |-
- From the official documentation https://docs.netbox.dev/en/stable/core-functionality/virtualization/#cluster-types:
+ From the official documentation https://docs.netbox.dev/en/stable/features/virtualization/#cluster-types:
A cluster type represents a technology or mechanism by which a cluster is formed. For example, you might create a cluster type named "VMware vSphere" for a locally hosted cluster or "DigitalOcean NYC3" for one hosted by a cloud provider.
---
# netbox_cluster_type (Resource)
-From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/virtualization/#cluster-types):
+From the [official documentation](https://docs.netbox.dev/en/stable/features/virtualization/#cluster-types):
> A cluster type represents a technology or mechanism by which a cluster is formed. For example, you might create a cluster type named "VMware vSphere" for a locally hosted cluster or "DigitalOcean NYC3" for one hosted by a cloud provider.
diff --git a/docs/resources/contact.md b/docs/resources/contact.md
new file mode 100644
index 00000000..75515a73
--- /dev/null
+++ b/docs/resources/contact.md
@@ -0,0 +1,39 @@
+---
+# generated by https://github.com/fbreckle/terraform-plugin-docs
+page_title: "netbox_contact Resource - terraform-provider-netbox"
+subcategory: "Tenancy"
+description: |-
+ From the official documentation https://docs.netbox.dev/en/stable/features/contacts/#contacts_1:
+ A contact should represent an individual or permanent point of contact. Each contact must define a name, and may optionally include a title, phone number, email address, and related details.
+ Contacts are reused for assignments, so each unique contact must be created only once and can be assigned to any number of NetBox objects, and there is no limit to the number of assigned contacts an object may have. Most core objects in NetBox can have contacts assigned to them.
+---
+
+# netbox_contact (Resource)
+
+From the [official documentation](https://docs.netbox.dev/en/stable/features/contacts/#contacts_1):
+
+> A contact should represent an individual or permanent point of contact. Each contact must define a name, and may optionally include a title, phone number, email address, and related details.
+>
+> Contacts are reused for assignments, so each unique contact must be created only once and can be assigned to any number of NetBox objects, and there is no limit to the number of assigned contacts an object may have. Most core objects in NetBox can have contacts assigned to them.
+
+
+
+
+## Schema
+
+### Required
+
+- `name` (String)
+
+### Optional
+
+- `email` (String)
+- `group_id` (Number)
+- `phone` (String)
+- `tags` (Set of String)
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+
diff --git a/docs/resources/contact_assignment.md b/docs/resources/contact_assignment.md
new file mode 100644
index 00000000..239a86ab
--- /dev/null
+++ b/docs/resources/contact_assignment.md
@@ -0,0 +1,32 @@
+---
+# generated by https://github.com/fbreckle/terraform-plugin-docs
+page_title: "netbox_contact_assignment Resource - terraform-provider-netbox"
+subcategory: "Tenancy"
+description: |-
+ From the official documentation https://docs.netbox.dev/en/stable/features/contacts#contactassignments_1:
+ Much like tenancy, contact assignment enables you to track ownership of resources modeled in NetBox.
+---
+
+# netbox_contact_assignment (Resource)
+
+From the [official documentation](https://docs.netbox.dev/en/stable/features/contacts#contactassignments_1):
+
+> Much like tenancy, contact assignment enables you to track ownership of resources modeled in NetBox.
+
+
+
+
+## Schema
+
+### Required
+
+- `contact_id` (Number)
+- `content_type` (String)
+- `object_id` (Number)
+- `role_id` (Number)
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+
diff --git a/docs/resources/contact_role.md b/docs/resources/contact_role.md
new file mode 100644
index 00000000..bd0b1a60
--- /dev/null
+++ b/docs/resources/contact_role.md
@@ -0,0 +1,33 @@
+---
+# generated by https://github.com/fbreckle/terraform-plugin-docs
+page_title: "netbox_contact_role Resource - terraform-provider-netbox"
+subcategory: "Tenancy"
+description: |-
+ From the official documentation https://docs.netbox.dev/en/stable/features/contacts/#contactroles:
+ A contact role defines the relationship of a contact to an assigned object. For example, you might define roles for administrative, operational, and emergency contacts
+---
+
+# netbox_contact_role (Resource)
+
+From the [official documentation](https://docs.netbox.dev/en/stable/features/contacts/#contactroles):
+
+> A contact role defines the relationship of a contact to an assigned object. For example, you might define roles for administrative, operational, and emergency contacts
+
+
+
+
+## Schema
+
+### Required
+
+- `name` (String)
+
+### Optional
+
+- `slug` (String)
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+
diff --git a/docs/resources/custom_field.md b/docs/resources/custom_field.md
index 233a9526..5c270b01 100644
--- a/docs/resources/custom_field.md
+++ b/docs/resources/custom_field.md
@@ -32,6 +32,7 @@ From the [official documentation](https://docs.netbox.dev/en/stable/customizatio
- `choices` (Set of String)
- `default` (String)
- `description` (String)
+- `group_name` (String)
- `label` (String)
- `required` (Boolean)
- `validation_maximum` (Number)
diff --git a/docs/resources/device.md b/docs/resources/device.md
index 36c3db89..4292dc2d 100644
--- a/docs/resources/device.md
+++ b/docs/resources/device.md
@@ -3,13 +3,13 @@
page_title: "netbox_device Resource - terraform-provider-netbox"
subcategory: "Data Center Inventory Management (DCIM)"
description: |-
- From the official documentation https://docs.netbox.dev/en/stable/core-functionality/devices/#devices:
+ From the official documentation https://docs.netbox.dev/en/stable/features/devices/#devices:
Every piece of hardware which is installed within a site or rack exists in NetBox as a device. Devices are measured in rack units (U) and can be half depth or full depth. A device may have a height of 0U: These devices do not consume vertical rack space and cannot be assigned to a particular rack unit. A common example of a 0U device is a vertically-mounted PDU.
---
# netbox_device (Resource)
-From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/devices/#devices):
+From the [official documentation](https://docs.netbox.dev/en/stable/features/devices/#devices):
> Every piece of hardware which is installed within a site or rack exists in NetBox as a device. Devices are measured in rack units (U) and can be half depth or full depth. A device may have a height of 0U: These devices do not consume vertical rack space and cannot be assigned to a particular rack unit. A common example of a 0U device is a vertically-mounted PDU.
@@ -64,7 +64,9 @@ resource "netbox_device" "test" {
- `comments` (String)
- `custom_fields` (Map of String)
- `location_id` (Number)
+- `platform_id` (Number)
- `serial` (String)
+- `status` (String) Defaults to `active`.
- `tags` (Set of String)
- `tenant_id` (Number)
@@ -72,5 +74,6 @@ resource "netbox_device" "test" {
- `id` (String) The ID of this resource.
- `primary_ipv4` (Number)
+- `primary_ipv6` (Number)
diff --git a/docs/resources/device_interface.md b/docs/resources/device_interface.md
new file mode 100644
index 00000000..cd4c8222
--- /dev/null
+++ b/docs/resources/device_interface.md
@@ -0,0 +1,43 @@
+---
+# generated by https://github.com/fbreckle/terraform-plugin-docs
+page_title: "netbox_device_interface Resource - terraform-provider-netbox"
+subcategory: "Data Center Inventory Management (DCIM)"
+description: |-
+ From the official documentation https://docs.netbox.dev/en/stable/features/device/#interface:
+ Interfaces in NetBox represent network interfaces used to exchange data with connected devices. On modern networks, these are most commonly Ethernet, but other types are supported as well. IP addresses and VLANs can be assigned to interfaces.
+---
+
+# netbox_device_interface (Resource)
+
+From the [official documentation](https://docs.netbox.dev/en/stable/features/device/#interface):
+
+> Interfaces in NetBox represent network interfaces used to exchange data with connected devices. On modern networks, these are most commonly Ethernet, but other types are supported as well. IP addresses and VLANs can be assigned to interfaces.
+
+
+
+
+## Schema
+
+### Required
+
+- `device_id` (Number)
+- `name` (String)
+- `type` (String)
+
+### Optional
+
+- `description` (String)
+- `enabled` (Boolean) Defaults to `true`.
+- `mac_address` (String)
+- `mgmtonly` (Boolean)
+- `mode` (String)
+- `mtu` (Number)
+- `tagged_vlans` (Set of Number)
+- `tags` (Set of String)
+- `untagged_vlan` (Number)
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+
diff --git a/docs/resources/device_role.md b/docs/resources/device_role.md
index e5365c39..1e12b9cf 100644
--- a/docs/resources/device_role.md
+++ b/docs/resources/device_role.md
@@ -3,13 +3,13 @@
page_title: "netbox_device_role Resource - terraform-provider-netbox"
subcategory: "Data Center Inventory Management (DCIM)"
description: |-
- From the official documentation https://docs.netbox.dev/en/stable/core-functionality/devices/#device-roles:
+ From the official documentation https://docs.netbox.dev/en/stable/features/devices/#device-roles:
Devices can be organized by functional roles, which are fully customizable by the user. For example, you might create roles for core switches, distribution switches, and access switches within your network.
---
# netbox_device_role (Resource)
-From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/devices/#device-roles):
+From the [official documentation](https://docs.netbox.dev/en/stable/features/devices/#device-roles):
> Devices can be organized by functional roles, which are fully customizable by the user. For example, you might create roles for core switches, distribution switches, and access switches within your network.
@@ -33,6 +33,7 @@ resource "netbox_device_role" "core_sw" {
### Optional
- `slug` (String)
+- `tags` (Set of String)
- `vm_role` (Boolean) Defaults to `true`.
### Read-Only
diff --git a/docs/resources/device_type.md b/docs/resources/device_type.md
index 800c811a..920ed121 100644
--- a/docs/resources/device_type.md
+++ b/docs/resources/device_type.md
@@ -3,13 +3,13 @@
page_title: "netbox_device_type Resource - terraform-provider-netbox"
subcategory: "Data Center Inventory Management (DCIM)"
description: |-
- From the official documentation https://docs.netbox.dev/en/stable/core-functionality/device-types/#device-types_1:
+ From the official documentation https://docs.netbox.dev/en/stable/features/device-types/#device-types_1:
A device type represents a particular make and model of hardware that exists in the real world. Device types define the physical attributes of a device (rack height and depth) and its individual components (console, power, network interfaces, and so on).
---
# netbox_device_type (Resource)
-From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/device-types/#device-types_1):
+From the [official documentation](https://docs.netbox.dev/en/stable/features/device-types/#device-types_1):
> A device type represents a particular make and model of hardware that exists in the real world. Device types define the physical attributes of a device (rack height and depth) and its individual components (console, power, network interfaces, and so on).
diff --git a/docs/resources/interface.md b/docs/resources/interface.md
index 3d385737..681e0f58 100644
--- a/docs/resources/interface.md
+++ b/docs/resources/interface.md
@@ -3,13 +3,13 @@
page_title: "netbox_interface Resource - terraform-provider-netbox"
subcategory: "Virtualization"
description: |-
- From the official documentation https://docs.netbox.dev/en/stable/core-functionality/virtualization/#interfaces:
+ From the official documentation https://docs.netbox.dev/en/stable/features/virtualization/#interfaces:
Virtual machine interfaces behave similarly to device interfaces, and can be assigned to VRFs, and may have IP addresses, VLANs, and services attached to them. However, given their virtual nature, they lack properties pertaining to physical attributes. For example, VM interfaces do not have a physical type and cannot have cables attached to them.
---
# netbox_interface (Resource)
-From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/virtualization/#interfaces):
+From the [official documentation](https://docs.netbox.dev/en/stable/features/virtualization/#interfaces):
> Virtual machine interfaces behave similarly to device interfaces, and can be assigned to VRFs, and may have IP addresses, VLANs, and services attached to them. However, given their virtual nature, they lack properties pertaining to physical attributes. For example, VM interfaces do not have a physical type and cannot have cables attached to them.
diff --git a/docs/resources/ip_address.md b/docs/resources/ip_address.md
index 07fa4512..861e28c0 100644
--- a/docs/resources/ip_address.md
+++ b/docs/resources/ip_address.md
@@ -3,14 +3,14 @@
page_title: "netbox_ip_address Resource - terraform-provider-netbox"
subcategory: "IP Address Management (IPAM)"
description: |-
- From the official documentation https://docs.netbox.dev/en/stable/core-functionality/ipam/#ip-addresses:
+ From the official documentation https://docs.netbox.dev/en/stable/features/ipam/#ip-addresses:
An IP address comprises a single host address (either IPv4 or IPv6) and its subnet mask. Its mask should match exactly how the IP address is configured on an interface in the real world.
Like a prefix, an IP address can optionally be assigned to a VRF (otherwise, it will appear in the "global" table). IP addresses are automatically arranged under parent prefixes within their respective VRFs according to the IP hierarchy.
---
# netbox_ip_address (Resource)
-From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/ipam/#ip-addresses):
+From the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#ip-addresses):
> An IP address comprises a single host address (either IPv4 or IPv6) and its subnet mask. Its mask should match exactly how the IP address is configured on an interface in the real world.
>
diff --git a/docs/resources/ip_range.md b/docs/resources/ip_range.md
index a53f395f..70f68d4f 100644
--- a/docs/resources/ip_range.md
+++ b/docs/resources/ip_range.md
@@ -3,13 +3,13 @@
page_title: "netbox_ip_range Resource - terraform-provider-netbox"
subcategory: "IP Address Management (IPAM)"
description: |-
- From the official documentation https://docs.netbox.dev/en/stable/core-functionality/ipam/#ip-ranges:
+ From the official documentation https://docs.netbox.dev/en/stable/features/ipam/#ip-ranges:
This model represents an arbitrary range of individual IPv4 or IPv6 addresses, inclusive of its starting and ending addresses. For instance, the range 192.0.2.10 to 192.0.2.20 has eleven members. (The total member count is available as the size property on an IPRange instance.) Like prefixes and IP addresses, each IP range may optionally be assigned to a VRF and/or tenant.
---
# netbox_ip_range (Resource)
-From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/ipam/#ip-ranges):
+From the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#ip-ranges):
> This model represents an arbitrary range of individual IPv4 or IPv6 addresses, inclusive of its starting and ending addresses. For instance, the range 192.0.2.10 to 192.0.2.20 has eleven members. (The total member count is available as the size property on an IPRange instance.) Like prefixes and IP addresses, each IP range may optionally be assigned to a VRF and/or tenant.
diff --git a/docs/resources/ipam_role.md b/docs/resources/ipam_role.md
index b812fa3a..9ca104e7 100644
--- a/docs/resources/ipam_role.md
+++ b/docs/resources/ipam_role.md
@@ -3,13 +3,13 @@
page_title: "netbox_ipam_role Resource - terraform-provider-netbox"
subcategory: "IP Address Management (IPAM)"
description: |-
- From the official documentation https://docs.netbox.dev/en/stable/core-functionality/ipam/#prefixvlan-roles:
+ From the official documentation https://docs.netbox.dev/en/stable/features/ipam/#prefixvlan-roles:
A role indicates the function of a prefix or VLAN. For example, you might define Data, Voice, and Security roles. Generally, a prefix will be assigned the same functional role as the VLAN to which it is assigned (if any).
---
# netbox_ipam_role (Resource)
-From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/ipam/#prefixvlan-roles):
+From the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#prefixvlan-roles):
> A role indicates the function of a prefix or VLAN. For example, you might define Data, Voice, and Security roles. Generally, a prefix will be assigned the same functional role as the VLAN to which it is assigned (if any).
diff --git a/docs/resources/location.md b/docs/resources/location.md
index 1b150ae6..6d1176be 100644
--- a/docs/resources/location.md
+++ b/docs/resources/location.md
@@ -3,14 +3,14 @@
page_title: "netbox_location Resource - terraform-provider-netbox"
subcategory: "Data Center Inventory Management (DCIM)"
description: |-
- From the official documentation https://docs.netbox.dev/en/stable/core-functionality/sites-and-racks/#locations:
+ From the official documentation https://docs.netbox.dev/en/stable/features/sites-and-racks/#locations:
Racks and devices can be grouped by location within a site. A location may represent a floor, room, cage, or similar organizational unit. Locations can be nested to form a hierarchy. For example, you may have floors within a site, and rooms within a floor.
Each location must have a name that is unique within its parent site and location, if any.
---
# netbox_location (Resource)
-From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/sites-and-racks/#locations):
+From the [official documentation](https://docs.netbox.dev/en/stable/features/sites-and-racks/#locations):
> Racks and devices can be grouped by location within a site. A location may represent a floor, room, cage, or similar organizational unit. Locations can be nested to form a hierarchy. For example, you may have floors within a site, and rooms within a floor.
diff --git a/docs/resources/manufacturer.md b/docs/resources/manufacturer.md
index a23586b7..3663205c 100644
--- a/docs/resources/manufacturer.md
+++ b/docs/resources/manufacturer.md
@@ -3,13 +3,13 @@
page_title: "netbox_manufacturer Resource - terraform-provider-netbox"
subcategory: "Data Center Inventory Management (DCIM)"
description: |-
- From the official documentation https://docs.netbox.dev/en/stable/core-functionality/device-types/#manufacturers:
+ From the official documentation https://docs.netbox.dev/en/stable/features/device-types/#manufacturers:
A manufacturer represents the "make" of a device; e.g. Cisco or Dell. Each device type must be assigned to a manufacturer. (Inventory items and platforms may also be associated with manufacturers.) Each manufacturer must have a unique name and may have a description assigned to it.
---
# netbox_manufacturer (Resource)
-From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/device-types/#manufacturers):
+From the [official documentation](https://docs.netbox.dev/en/stable/features/device-types/#manufacturers):
> A manufacturer represents the "make" of a device; e.g. Cisco or Dell. Each device type must be assigned to a manufacturer. (Inventory items and platforms may also be associated with manufacturers.) Each manufacturer must have a unique name and may have a description assigned to it.
diff --git a/docs/resources/platform.md b/docs/resources/platform.md
index e764e6cd..872b59b7 100644
--- a/docs/resources/platform.md
+++ b/docs/resources/platform.md
@@ -3,13 +3,13 @@
page_title: "netbox_platform Resource - terraform-provider-netbox"
subcategory: "Data Center Inventory Management (DCIM)"
description: |-
- From the official documentation https://docs.netbox.dev/en/stable/core-functionality/devices/#platforms:
+ From the official documentation https://docs.netbox.dev/en/stable/features/devices/#platforms:
A platform defines the type of software running on a device or virtual machine. This can be helpful to model when it is necessary to distinguish between different versions or feature sets. Note that two devices of the same type may be assigned different platforms: For example, one Juniper MX240 might run Junos 14 while another runs Junos 15.
---
# netbox_platform (Resource)
-From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/devices/#platforms):
+From the [official documentation](https://docs.netbox.dev/en/stable/features/devices/#platforms):
> A platform defines the type of software running on a device or virtual machine. This can be helpful to model when it is necessary to distinguish between different versions or feature sets. Note that two devices of the same type may be assigned different platforms: For example, one Juniper MX240 might run Junos 14 while another runs Junos 15.
diff --git a/docs/resources/prefix.md b/docs/resources/prefix.md
index 6c7b5f52..fdb90223 100644
--- a/docs/resources/prefix.md
+++ b/docs/resources/prefix.md
@@ -3,14 +3,14 @@
page_title: "netbox_prefix Resource - terraform-provider-netbox"
subcategory: "IP Address Management (IPAM)"
description: |-
- From the official documentation https://docs.netbox.dev/en/stable/core-functionality/ipam/#prefixes:
+ From the official documentation https://docs.netbox.dev/en/stable/features/ipam/#prefixes:
A prefix is an IPv4 or IPv6 network and mask expressed in CIDR notation (e.g. 192.0.2.0/24). A prefix entails only the "network portion" of an IP address: All bits in the address not covered by the mask must be zero. (In other words, a prefix cannot be a specific IP address.)
Prefixes are automatically organized by their parent aggregates. Additionally, each prefix can be assigned to a particular site and virtual routing and forwarding instance (VRF). Each VRF represents a separate IP space or routing table. All prefixes not assigned to a VRF are considered to be in the "global" table.
---
# netbox_prefix (Resource)
-From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/ipam/#prefixes):
+From the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#prefixes):
> A prefix is an IPv4 or IPv6 network and mask expressed in CIDR notation (e.g. 192.0.2.0/24). A prefix entails only the "network portion" of an IP address: All bits in the address not covered by the mask must be zero. (In other words, a prefix cannot be a specific IP address.)
>
diff --git a/docs/resources/region.md b/docs/resources/region.md
index 44436265..19325b26 100644
--- a/docs/resources/region.md
+++ b/docs/resources/region.md
@@ -3,14 +3,14 @@
page_title: "netbox_region Resource - terraform-provider-netbox"
subcategory: "Data Center Inventory Management (DCIM)"
description: |-
- From the official documentation https://docs.netbox.dev/en/stable/core-functionality/sites-and-racks/#regions:
+ From the official documentation https://docs.netbox.dev/en/stable/features/sites-and-racks/#regions:
Sites can be arranged geographically using regions. A region might represent a continent, country, city, campus, or other area depending on your use case. Regions can be nested recursively to construct a hierarchy. For example, you might define several country regions, and within each of those several state or city regions to which sites are assigned.
Each region must have a name that is unique within its parent region, if any.
---
# netbox_region (Resource)
-From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/sites-and-racks/#regions):
+From the [official documentation](https://docs.netbox.dev/en/stable/features/sites-and-racks/#regions):
> Sites can be arranged geographically using regions. A region might represent a continent, country, city, campus, or other area depending on your use case. Regions can be nested recursively to construct a hierarchy. For example, you might define several country regions, and within each of those several state or city regions to which sites are assigned.
>
diff --git a/docs/resources/rir.md b/docs/resources/rir.md
index ddc8de29..62d916dc 100644
--- a/docs/resources/rir.md
+++ b/docs/resources/rir.md
@@ -3,13 +3,13 @@
page_title: "netbox_rir Resource - terraform-provider-netbox"
subcategory: "IP Address Management (IPAM)"
description: |-
- From the official documentation https://docs.netbox.dev/en/stable/core-functionality/ipam/#regional-internet-registries-rirs:
+ From the official documentation https://docs.netbox.dev/en/stable/features/ipam/#regional-internet-registries-rirs:
Regional Internet registries are responsible for the allocation of globally-routable address space. The five RIRs are ARIN, RIPE, APNIC, LACNIC, and AFRINIC. However, some address space has been set aside for internal use, such as defined in RFCs 1918 and 6598. NetBox considers these RFCs as a sort of RIR as well; that is, an authority which "owns" certain address space. There also exist lower-tier registries which serve particular geographic areas.
---
# netbox_rir (Resource)
-From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/ipam/#regional-internet-registries-rirs):
+From the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#regional-internet-registries-rirs):
> Regional Internet registries are responsible for the allocation of globally-routable address space. The five RIRs are ARIN, RIPE, APNIC, LACNIC, and AFRINIC. However, some address space has been set aside for internal use, such as defined in RFCs 1918 and 6598. NetBox considers these RFCs as a sort of RIR as well; that is, an authority which "owns" certain address space. There also exist lower-tier registries which serve particular geographic areas.
diff --git a/docs/resources/service.md b/docs/resources/service.md
index db2d2ff1..a395a40f 100644
--- a/docs/resources/service.md
+++ b/docs/resources/service.md
@@ -3,14 +3,14 @@
page_title: "netbox_service Resource - terraform-provider-netbox"
subcategory: "IP Address Management (IPAM)"
description: |-
- From the official documentation https://docs.netbox.dev/en/stable/core-functionality/services/#services:
+ From the official documentation https://docs.netbox.dev/en/stable/features/services/#services:
A service represents a layer four TCP or UDP service available on a device or virtual machine. For example, you might want to document that an HTTP service is running on a device. Each service includes a name, protocol, and port number; for example, "SSH (TCP/22)" or "DNS (UDP/53)."
A service may optionally be bound to one or more specific IP addresses belonging to its parent device or VM. (If no IP addresses are bound, the service is assumed to be reachable via any assigned IP address.
---
# netbox_service (Resource)
-From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/services/#services):
+From the [official documentation](https://docs.netbox.dev/en/stable/features/services/#services):
> A service represents a layer four TCP or UDP service available on a device or virtual machine. For example, you might want to document that an HTTP service is running on a device. Each service includes a name, protocol, and port number; for example, "SSH (TCP/22)" or "DNS (UDP/53)."
>
@@ -27,7 +27,7 @@ data "netbox_virtual_machine" "myvm" {
resource "netbox_service" "ssh" {
name = "ssh"
ports = [22]
- protocol = "TCP"
+ protocol = "tcp"
virtual_machine_id = data.netbox_virtual_machine.myvm.id
}
```
diff --git a/docs/resources/site.md b/docs/resources/site.md
index 2605e87a..8d23f24e 100644
--- a/docs/resources/site.md
+++ b/docs/resources/site.md
@@ -3,14 +3,14 @@
page_title: "netbox_site Resource - terraform-provider-netbox"
subcategory: "Data Center Inventory Management (DCIM)"
description: |-
- From the official documentation https://docs.netbox.dev/en/stable/core-functionality/sites-and-racks/#sites:
+ From the official documentation https://docs.netbox.dev/en/stable/features/sites-and-racks/#sites:
How you choose to employ sites when modeling your network may vary depending on the nature of your organization, but generally a site will equate to a building or campus. For example, a chain of banks might create a site to represent each of its branches, a site for its corporate headquarters, and two additional sites for its presence in two colocation facilities.
Each site must be assigned a unique name and may optionally be assigned to a region and/or tenant.
---
# netbox_site (Resource)
-From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/sites-and-racks/#sites):
+From the [official documentation](https://docs.netbox.dev/en/stable/features/sites-and-racks/#sites):
> How you choose to employ sites when modeling your network may vary depending on the nature of your organization, but generally a site will equate to a building or campus. For example, a chain of banks might create a site to represent each of its branches, a site for its corporate headquarters, and two additional sites for its presence in two colocation facilities.
>
@@ -43,6 +43,7 @@ resource "netbox_site" "example1" {
- `custom_fields` (Map of String)
- `description` (String)
- `facility` (String)
+- `group_id` (Number)
- `latitude` (Number)
- `longitude` (Number)
- `region_id` (Number)
diff --git a/docs/resources/tenant.md b/docs/resources/tenant.md
index 8fc03efe..f23dd842 100644
--- a/docs/resources/tenant.md
+++ b/docs/resources/tenant.md
@@ -3,14 +3,14 @@
page_title: "netbox_tenant Resource - terraform-provider-netbox"
subcategory: "Tenancy"
description: |-
- From the official documentation https://docs.netbox.dev/en/stable/core-functionality/tenancy/#tenants:
+ From the official documentation https://docs.netbox.dev/en/stable/features/tenancy/#tenants:
A tenant represents a discrete grouping of resources used for administrative purposes. Typically, tenants are used to represent individual customers or internal departments within an organization.
Tenant assignment is used to signify the ownership of an object in NetBox. As such, each object may only be owned by a single tenant. For example, if you have a firewall dedicated to a particular customer, you would assign it to the tenant which represents that customer. However, if the firewall serves multiple customers, it doesn't belong to any particular customer, so tenant assignment would not be appropriate.
---
# netbox_tenant (Resource)
-From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/tenancy/#tenants):
+From the [official documentation](https://docs.netbox.dev/en/stable/features/tenancy/#tenants):
> A tenant represents a discrete grouping of resources used for administrative purposes. Typically, tenants are used to represent individual customers or internal departments within an organization.
>
@@ -33,6 +33,7 @@ resource "netbox_tenant" "customer_a" {
### Optional
+- `description` (String)
- `group_id` (Number)
- `slug` (String)
- `tags` (Set of String)
diff --git a/docs/resources/tenant_group.md b/docs/resources/tenant_group.md
index 0caf9793..e2888467 100644
--- a/docs/resources/tenant_group.md
+++ b/docs/resources/tenant_group.md
@@ -3,14 +3,14 @@
page_title: "netbox_tenant_group Resource - terraform-provider-netbox"
subcategory: "Tenancy"
description: |-
- From the official documentation https://docs.netbox.dev/en/stable/core-functionality/tenancy/#tenant-groups:
+ From the official documentation https://docs.netbox.dev/en/stable/features/tenancy/#tenant-groups:
Tenants can be organized by custom groups. For instance, you might create one group called "Customers" and one called "Departments." The assignment of a tenant to a group is optional.
Tenant groups may be nested recursively to achieve a multi-level hierarchy. For example, you might have a group called "Customers" containing subgroups of individual tenants grouped by product or account team.
---
# netbox_tenant_group (Resource)
-From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/tenancy/#tenant-groups):
+From the [official documentation](https://docs.netbox.dev/en/stable/features/tenancy/#tenant-groups):
> Tenants can be organized by custom groups. For instance, you might create one group called "Customers" and one called "Departments." The assignment of a tenant to a group is optional.
>
diff --git a/docs/resources/virtual_machine.md b/docs/resources/virtual_machine.md
index 3fda48ac..2d4f913d 100644
--- a/docs/resources/virtual_machine.md
+++ b/docs/resources/virtual_machine.md
@@ -3,18 +3,15 @@
page_title: "netbox_virtual_machine Resource - terraform-provider-netbox"
subcategory: "Virtualization"
description: |-
- From the official documentation https://docs.netbox.dev/en/stable/core-functionality/virtualization/#virtual-machines:
- A virtual machine represents a virtual compute instance hosted within a cluster. Each VM must be assigned to exactly one cluster.
- Like devices, each VM can be assigned a platform and/or functional role
+ From the official documentation https://docs.netbox.dev/en/stable/features/virtualization/#virtual-machines:
+ A virtual machine is a virtualized compute instance. These behave in NetBox very similarly to device objects, but without any physical attributes. For example, a VM may have interfaces assigned to it with IP addresses and VLANs, however its interfaces cannot be connected via cables (because they are virtual). Each VM may also define its compute, memory, and storage resources as well.
---
# netbox_virtual_machine (Resource)
-From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/virtualization/#virtual-machines):
+From the [official documentation](https://docs.netbox.dev/en/stable/features/virtualization/#virtual-machines):
-> A virtual machine represents a virtual compute instance hosted within a cluster. Each VM must be assigned to exactly one cluster.
->
-> Like devices, each VM can be assigned a platform and/or functional role
+> A virtual machine is a virtualized compute instance. These behave in NetBox very similarly to device objects, but without any physical attributes. For example, a VM may have interfaces assigned to it with IP addresses and VLANs, however its interfaces cannot be connected via cables (because they are virtual). Each VM may also define its compute, memory, and storage resources as well.
## Example Usage
@@ -70,7 +67,7 @@ resource "netbox_virtual_machine" "full_vm" {
### Optional
-- `cluster_id` (Number) If this is set to a cluster that has a site, you have to set `site_id` as well. At least one of `site_id` or `cluster_id` must be given.
+- `cluster_id` (Number) At least one of `site_id` or `cluster_id` must be given.
- `comments` (String)
- `custom_fields` (Map of String)
- `device_id` (Number)
@@ -88,5 +85,6 @@ resource "netbox_virtual_machine" "full_vm" {
- `id` (String) The ID of this resource.
- `primary_ipv4` (Number)
+- `primary_ipv6` (Number)
diff --git a/docs/resources/vlan.md b/docs/resources/vlan.md
index a71ac0fa..2d728184 100644
--- a/docs/resources/vlan.md
+++ b/docs/resources/vlan.md
@@ -3,13 +3,13 @@
page_title: "netbox_vlan Resource - terraform-provider-netbox"
subcategory: "IP Address Management (IPAM)"
description: |-
- From the official documentation https://docs.netbox.dev/en/stable/core-functionality/vlans/#vlans:
+ From the official documentation https://docs.netbox.dev/en/stable/features/vlans/#vlans:
A VLAN represents an isolated layer two domain, identified by a name and a numeric ID (1-4094) as defined in IEEE 802.1Q. VLANs are arranged into VLAN groups to define scope and to enforce uniqueness.
---
# netbox_vlan (Resource)
-From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/vlans/#vlans):
+From the [official documentation](https://docs.netbox.dev/en/stable/features/vlans/#vlans):
> A VLAN represents an isolated layer two domain, identified by a name and a numeric ID (1-4094) as defined in IEEE 802.1Q. VLANs are arranged into VLAN groups to define scope and to enforce uniqueness.
diff --git a/docs/resources/vrf.md b/docs/resources/vrf.md
index 35272e92..370d2955 100644
--- a/docs/resources/vrf.md
+++ b/docs/resources/vrf.md
@@ -3,13 +3,13 @@
page_title: "netbox_vrf Resource - terraform-provider-netbox"
subcategory: "IP Address Management (IPAM)"
description: |-
- From the official documentation https://docs.netbox.dev/en/stable/core-functionality/ipam/#virtual-routing-and-forwarding-vrf:
+ From the official documentation https://docs.netbox.dev/en/stable/features/ipam/#virtual-routing-and-forwarding-vrf:
A VRF object in NetBox represents a virtual routing and forwarding (VRF) domain. Each VRF is essentially a separate routing table. VRFs are commonly used to isolate customers or organizations from one another within a network, or to route overlapping address space (e.g. multiple instances of the 10.0.0.0/8 space). Each VRF may be assigned to a specific tenant to aid in organizing the available IP space by customer or internal user.
---
# netbox_vrf (Resource)
-From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/ipam/#virtual-routing-and-forwarding-vrf):
+From the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#virtual-routing-and-forwarding-vrf):
> A VRF object in NetBox represents a virtual routing and forwarding (VRF) domain. Each VRF is essentially a separate routing table. VRFs are commonly used to isolate customers or organizations from one another within a network, or to route overlapping address space (e.g. multiple instances of the 10.0.0.0/8 space). Each VRF may be assigned to a specific tenant to aid in organizing the available IP space by customer or internal user.
diff --git a/examples/data-sources/netbox_asn/data-source.tf b/examples/data-sources/netbox_asn/data-source.tf
new file mode 100644
index 00000000..ad26b723
--- /dev/null
+++ b/examples/data-sources/netbox_asn/data-source.tf
@@ -0,0 +1,9 @@
+data "netbox_asn" "asn_1" {
+ asn = "1111"
+ tag = "tag-1"
+}
+
+data "netbox_asn" "asn_2" {
+ tag = "tag-1"
+ tag__n = "tag-2"
+}
diff --git a/examples/data-sources/netbox_asns/data-source.tf b/examples/data-sources/netbox_asns/data-source.tf
new file mode 100644
index 00000000..f610887b
--- /dev/null
+++ b/examples/data-sources/netbox_asns/data-source.tf
@@ -0,0 +1,10 @@
+data "netbox_asns" "asns" {
+ filter {
+ name = "asn__gte"
+ value = "1000"
+ }
+ filter {
+ name = "asn__lte"
+ value = "2000"
+ }
+}
\ No newline at end of file
diff --git a/examples/data-sources/netbox_vlan/data-source.tf b/examples/data-sources/netbox_vlan/data-source.tf
index d4a87ded..b22db2b1 100644
--- a/examples/data-sources/netbox_vlan/data-source.tf
+++ b/examples/data-sources/netbox_vlan/data-source.tf
@@ -3,7 +3,14 @@ data "netbox_vlan" "vlan1" {
name = "vlan-1"
}
-# Get VLAN by VLAN ID
+# Get VLAN by VID and IPAM role ID
data "netbox_vlan" "vlan2" {
- vid = 1234
+ vid = 1234
+ role = netbox_ipam_role.example.id
+}
+
+# Get VLAN by name and tenant ID
+data "netbox_vlan" "vlan3" {
+ name = "vlan-3"
+ tenant = netbox_tenant.example.id
}
diff --git a/examples/resources/netbox_service/resource.tf b/examples/resources/netbox_service/resource.tf
index 3af09802..f886c3f0 100644
--- a/examples/resources/netbox_service/resource.tf
+++ b/examples/resources/netbox_service/resource.tf
@@ -6,6 +6,6 @@ data "netbox_virtual_machine" "myvm" {
resource "netbox_service" "ssh" {
name = "ssh"
ports = [22]
- protocol = "TCP"
+ protocol = "tcp"
virtual_machine_id = data.netbox_virtual_machine.myvm.id
}
diff --git a/go.mod b/go.mod
index 87da2997..3750361c 100644
--- a/go.mod
+++ b/go.mod
@@ -4,14 +4,15 @@ go 1.19
require (
github.com/davecgh/go-spew v1.1.1
- github.com/fbreckle/go-netbox v0.0.0-20220927145419-8900c6193f4e
+ github.com/fbreckle/go-netbox v0.0.0-20221018092604-4430d729e292
github.com/fbreckle/terraform-plugin-docs v0.0.0-20220812121758-a828466500d3
- github.com/go-openapi/runtime v0.24.1
+ github.com/go-openapi/runtime v0.24.2
+ github.com/go-openapi/strfmt v0.21.3
github.com/goware/urlx v0.3.2
- github.com/hashicorp/terraform-plugin-sdk/v2 v2.23.0
+ github.com/hashicorp/terraform-plugin-sdk/v2 v2.24.1
github.com/sirupsen/logrus v1.9.0
- github.com/stretchr/testify v1.8.0
- golang.org/x/exp v0.0.0-20220921164117-439092de6870
+ github.com/stretchr/testify v1.8.1
+ golang.org/x/exp v0.0.0-20221002003631-540bb7301a08
)
require (
@@ -32,7 +33,6 @@ require (
github.com/go-openapi/jsonreference v0.20.0 // indirect
github.com/go-openapi/loads v0.21.2 // indirect
github.com/go-openapi/spec v0.20.7 // indirect
- github.com/go-openapi/strfmt v0.21.3 // indirect
github.com/go-openapi/swag v0.22.3 // indirect
github.com/go-openapi/validate v0.22.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
@@ -44,15 +44,15 @@ require (
github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 // indirect
github.com/hashicorp/go-hclog v1.3.1 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
- github.com/hashicorp/go-plugin v1.4.5 // indirect
+ github.com/hashicorp/go-plugin v1.4.6 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect
github.com/hashicorp/go-version v1.6.0 // indirect
github.com/hashicorp/hc-install v0.4.0 // indirect
- github.com/hashicorp/hcl/v2 v2.14.1 // indirect
+ github.com/hashicorp/hcl/v2 v2.15.0 // indirect
github.com/hashicorp/logutils v1.0.0 // indirect
github.com/hashicorp/terraform-exec v0.17.3 // indirect
github.com/hashicorp/terraform-json v0.14.0 // indirect
- github.com/hashicorp/terraform-plugin-go v0.14.0 // indirect
+ github.com/hashicorp/terraform-plugin-go v0.14.1 // indirect
github.com/hashicorp/terraform-plugin-log v0.7.0 // indirect
github.com/hashicorp/terraform-registry-address v0.0.0-20220623143253-7d51757b572c // indirect
github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 // indirect
@@ -80,15 +80,15 @@ require (
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
github.com/vmihailenco/msgpack/v4 v4.3.12 // indirect
github.com/vmihailenco/tagparser v0.1.2 // indirect
- github.com/zclconf/go-cty v1.11.0 // indirect
+ github.com/zclconf/go-cty v1.12.1 // indirect
go.mongodb.org/mongo-driver v1.10.2 // indirect
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be // indirect
- golang.org/x/net v0.0.0-20220926192436-02166a98028e // indirect
- golang.org/x/sys v0.0.0-20220926163933-8cfa568d3c25 // indirect
+ golang.org/x/net v0.0.0-20221004154528-8021a29435af // indirect
+ golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
golang.org/x/text v0.3.7 // indirect
google.golang.org/appengine v1.6.7 // indirect
- google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce // indirect
- google.golang.org/grpc v1.49.0 // indirect
+ google.golang.org/genproto v0.0.0-20220930163606-c98284e70a91 // indirect
+ google.golang.org/grpc v1.50.1 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
diff --git a/go.sum b/go.sum
index 4000cb86..8e1d3ea6 100644
--- a/go.sum
+++ b/go.sum
@@ -48,8 +48,8 @@ github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
-github.com/fbreckle/go-netbox v0.0.0-20220927145419-8900c6193f4e h1:d91o32JjciVNSFYX6RtC+aPwq4aSt+6sM1Dmcp28Q9E=
-github.com/fbreckle/go-netbox v0.0.0-20220927145419-8900c6193f4e/go.mod h1:3U3/m/hna9Ntd3sbHBYwZ1IqbP2+coRzoXw3mCfu3kM=
+github.com/fbreckle/go-netbox v0.0.0-20221018092604-4430d729e292 h1:j6sIt1qjrPd5bGvjcsJlehZnCxXb4J3Ogz/pExEt1vI=
+github.com/fbreckle/go-netbox v0.0.0-20221018092604-4430d729e292/go.mod h1:3U3/m/hna9Ntd3sbHBYwZ1IqbP2+coRzoXw3mCfu3kM=
github.com/fbreckle/terraform-plugin-docs v0.0.0-20220812121758-a828466500d3 h1:DMSpM0btVedE2Tt1vfDHWQhf2obzjAe1F0/j8/CyfW4=
github.com/fbreckle/terraform-plugin-docs v0.0.0-20220812121758-a828466500d3/go.mod h1:j3HmJySEjx6hOAOPDjGzmzpVNDQq9SNnnF+Vm22d2rs=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
@@ -80,8 +80,8 @@ github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXym
github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g=
github.com/go-openapi/loads v0.21.2 h1:r2a/xFIYeZ4Qd2TnGpWDIQNcP80dIaZgf704za8enro=
github.com/go-openapi/loads v0.21.2/go.mod h1:Jq58Os6SSGz0rzh62ptiu8Z31I+OTHqmULx5e/gJbNw=
-github.com/go-openapi/runtime v0.24.1 h1:Sml5cgQKGYQHF+M7yYSHaH1eOjvTykrddTE/KtQVjqo=
-github.com/go-openapi/runtime v0.24.1/go.mod h1:AKurw9fNre+h3ELZfk6ILsfvPN+bvvlaU/M9q/r9hpk=
+github.com/go-openapi/runtime v0.24.2 h1:yX9HMGQbz32M87ECaAhGpJjBmErO3QLcgdZj9BzGx7c=
+github.com/go-openapi/runtime v0.24.2/go.mod h1:AKurw9fNre+h3ELZfk6ILsfvPN+bvvlaU/M9q/r9hpk=
github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I=
github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA=
github.com/go-openapi/spec v0.20.7 h1:1Rlu/ZrOCCob0n+JKKJAWhNWMPW8bOZRg8FJaY+0SKI=
@@ -163,8 +163,8 @@ github.com/hashicorp/go-hclog v1.3.1/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVH
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
-github.com/hashicorp/go-plugin v1.4.5 h1:oTE/oQR4eghggRg8VY7PAz3dr++VwDNBGCcOfIvHpBo=
-github.com/hashicorp/go-plugin v1.4.5/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s=
+github.com/hashicorp/go-plugin v1.4.6 h1:MDV3UrKQBM3du3G7MApDGvOsMYy3JQJ4exhSoKBAeVA=
+github.com/hashicorp/go-plugin v1.4.6/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
@@ -174,20 +174,20 @@ github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mO
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/hc-install v0.4.0 h1:cZkRFr1WVa0Ty6x5fTvL1TuO1flul231rWkGH92oYYk=
github.com/hashicorp/hc-install v0.4.0/go.mod h1:5d155H8EC5ewegao9A4PUTMNPZaq+TbOzkJJZ4vrXeI=
-github.com/hashicorp/hcl/v2 v2.14.1 h1:x0BpjfZ+CYdbiz+8yZTQ+gdLO7IXvOut7Da+XJayx34=
-github.com/hashicorp/hcl/v2 v2.14.1/go.mod h1:e4z5nxYlWNPdDSNYX+ph14EvWYMFm3eP0zIUqPc2jr0=
+github.com/hashicorp/hcl/v2 v2.15.0 h1:CPDXO6+uORPjKflkWCCwoWc9uRp+zSIPcCQ+BrxV7m8=
+github.com/hashicorp/hcl/v2 v2.15.0/go.mod h1:JRmR89jycNkrrqnMmvPDMd56n1rQJ2Q6KocSLCMCXng=
github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/terraform-exec v0.17.3 h1:MX14Kvnka/oWGmIkyuyvL6POx25ZmKrjlaclkx3eErU=
github.com/hashicorp/terraform-exec v0.17.3/go.mod h1:+NELG0EqQekJzhvikkeQsOAZpsw0cv/03rbeQJqscAI=
github.com/hashicorp/terraform-json v0.14.0 h1:sh9iZ1Y8IFJLx+xQiKHGud6/TSUCM0N8e17dKDpqV7s=
github.com/hashicorp/terraform-json v0.14.0/go.mod h1:5A9HIWPkk4e5aeeXIBbkcOvaZbIYnAIkEyqP2pNSckM=
-github.com/hashicorp/terraform-plugin-go v0.14.0 h1:ttnSlS8bz3ZPYbMb84DpcPhY4F5DsQtcAS7cHo8uvP4=
-github.com/hashicorp/terraform-plugin-go v0.14.0/go.mod h1:2nNCBeRLaenyQEi78xrGrs9hMbulveqG/zDMQSvVJTE=
+github.com/hashicorp/terraform-plugin-go v0.14.1 h1:cwZzPYla82XwAqpLhSzdVsOMU+6H29tczAwrB0z9Zek=
+github.com/hashicorp/terraform-plugin-go v0.14.1/go.mod h1:Bc/K6K26BQ2FHqIELPbpKtt2CzzbQou+0UQF3/0NsCQ=
github.com/hashicorp/terraform-plugin-log v0.7.0 h1:SDxJUyT8TwN4l5b5/VkiTIaQgY6R+Y2BQ0sRZftGKQs=
github.com/hashicorp/terraform-plugin-log v0.7.0/go.mod h1:p4R1jWBXRTvL4odmEkFfDdhUjHf9zcs/BCoNHAc7IK4=
-github.com/hashicorp/terraform-plugin-sdk/v2 v2.23.0 h1:D4EeQm0piYXIHp6ZH3zjyP2Elq6voC64x3GZptaiefA=
-github.com/hashicorp/terraform-plugin-sdk/v2 v2.23.0/go.mod h1:xkJGavPvP9kYS/VbiW8o7JuTNgPwm7Tiw/Ie/b46r4c=
+github.com/hashicorp/terraform-plugin-sdk/v2 v2.24.1 h1:zHcMbxY0+rFO9gY99elV/XC/UnQVg7FhRCbj1i5b7vM=
+github.com/hashicorp/terraform-plugin-sdk/v2 v2.24.1/go.mod h1:+tNlb0wkfdsDJ7JEiERLz4HzM19HyiuIoGzTsM7rPpw=
github.com/hashicorp/terraform-registry-address v0.0.0-20220623143253-7d51757b572c h1:D8aRO6+mTqHfLsK/BC3j5OAoogv1WLRWzY1AaTo3rBg=
github.com/hashicorp/terraform-registry-address v0.0.0-20220623143253-7d51757b572c/go.mod h1:Wn3Na71knbXc1G8Lh+yu/dQWWJeFQEpDeJMtWMtlmNI=
github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 h1:HKLsbzeOsfXmKNpr3GiT18XAblV0BjCbzL8KQAMZGa0=
@@ -305,6 +305,7 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -313,8 +314,9 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
-github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
@@ -336,8 +338,8 @@ github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7Jul
github.com/zclconf/go-cty v1.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s=
github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
github.com/zclconf/go-cty v1.10.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
-github.com/zclconf/go-cty v1.11.0 h1:726SxLdi2SDnjY+BStqB9J1hNp4+2WlzyXLuimibIe0=
-github.com/zclconf/go-cty v1.11.0/go.mod h1:s9IfD1LK5ccNMSWCVFCE2rJfHiZgi7JijgeWIMfhLvA=
+github.com/zclconf/go-cty v1.12.1 h1:PcupnljUm9EIvbgSHQnHhUr3fO6oFmkOrvs2BAFNXXY=
+github.com/zclconf/go-cty v1.12.1/go.mod h1:s9IfD1LK5ccNMSWCVFCE2rJfHiZgi7JijgeWIMfhLvA=
github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8=
go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg=
go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng=
@@ -359,8 +361,8 @@ golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be h1:fmw3UbQh+nxngCAHrDCCztao/kbYFnWjoqop8dHx05A=
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/exp v0.0.0-20220921164117-439092de6870 h1:j8b6j9gzSigH28O5SjSpQSSh9lFd6f5D/q0aHjNTulc=
-golang.org/x/exp v0.0.0-20220921164117-439092de6870/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
+golang.org/x/exp v0.0.0-20221002003631-540bb7301a08 h1:LtBIgSqNhkuC9gA3BFjGy5obHQT1lnmNsMDFSqWzQ5w=
+golang.org/x/exp v0.0.0-20221002003631-540bb7301a08/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -376,8 +378,8 @@ golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5o
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.0.0-20220926192436-02166a98028e h1:I51lVG9ykW5AQeTE50sJ0+gJCAF0J78Hf1+1VUCGxDI=
-golang.org/x/net v0.0.0-20220926192436-02166a98028e/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
+golang.org/x/net v0.0.0-20221004154528-8021a29435af h1:wv66FM3rLZGPdxpYL+ApnDe2HzHcTFta3z5nsc13wI4=
+golang.org/x/net v0.0.0-20221004154528-8021a29435af/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -412,8 +414,8 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220926163933-8cfa568d3c25 h1:nwzwVf0l2Y/lkov/+IYgMMbFyI+QypZDds9RxlSmsFQ=
-golang.org/x/sys v0.0.0-20220926163933-8cfa568d3c25/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI=
+golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
@@ -436,10 +438,10 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
-google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce h1:+2ye9vAK4F9F/LCex8dT2cDk0VnTAwUL8uRgX/6nAMU=
-google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI=
-google.golang.org/grpc v1.49.0 h1:WTLtQzmQori5FUH25Pq4WT22oCsv8USpQ+F6rqtsmxw=
-google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
+google.golang.org/genproto v0.0.0-20220930163606-c98284e70a91 h1:Ezh2cpcnP5Rq60sLensUsFnxh7P6513NLvNtCm9iyJ4=
+google.golang.org/genproto v0.0.0-20220930163606-c98284e70a91/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U=
+google.golang.org/grpc v1.50.1 h1:DS/BukOZWp8s6p4Dt/tOaJaTQyPyOoCcrjroHuCeLzY=
+google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
diff --git a/netbox/data_source_netbox_asn.go b/netbox/data_source_netbox_asn.go
new file mode 100644
index 00000000..fe1af079
--- /dev/null
+++ b/netbox/data_source_netbox_asn.go
@@ -0,0 +1,83 @@
+package netbox
+
+import (
+ "fmt"
+ "strconv"
+
+ "github.com/fbreckle/go-netbox/netbox/client"
+ "github.com/fbreckle/go-netbox/netbox/client/ipam"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+)
+
+func dataSourceNetboxAsn() *schema.Resource {
+ return &schema.Resource{
+ Read: dataSourceNetboxAsnRead,
+ Description: `:meta:subcategory:IP Address Management (IPAM):`,
+ Schema: map[string]*schema.Schema{
+ "id": {
+ Type: schema.TypeInt,
+ Computed: true,
+ },
+ "asn": {
+ Type: schema.TypeString,
+ Optional: true,
+ AtLeastOneOf: []string{"asn", "tag"},
+ },
+ "tag": {
+ Type: schema.TypeString,
+ Optional: true,
+ AtLeastOneOf: []string{"asn", "tag"},
+ Description: "Tag to include in the data source filter (must match the tag's slug).",
+ },
+ "tag__n": {
+ Type: schema.TypeString,
+ Optional: true,
+ Description: `Tag to exclude from the data source filter (must match the tag's slug).
+Refer to [Netbox's documentation](https://demo.netbox.dev/static/docs/rest-api/filtering/#lookup-expressions)
+for more information on available lookup expressions.`,
+ },
+ "description": {
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ "tags": tagsSchemaRead,
+ },
+ }
+}
+
+func dataSourceNetboxAsnRead(d *schema.ResourceData, m interface{}) error {
+ api := m.(*client.NetBoxAPI)
+
+ params := ipam.NewIpamAsnsListParams()
+
+ limit := int64(2) // Limit of 2 is enough
+ params.Limit = &limit
+
+ if asn, ok := d.Get("asn").(string); ok && asn != "" {
+ params.Asn = &asn
+ }
+
+ if tag, ok := d.Get("tag").(string); ok && tag != "" {
+ params.Tag = &tag
+ }
+ if tagn, ok := d.Get("tag__n").(string); ok && tagn != "" {
+ params.Tagn = &tagn
+ }
+
+ res, err := api.Ipam.IpamAsnsList(params, nil)
+ if err != nil {
+ return err
+ }
+
+ if count := *res.GetPayload().Count; count != int64(1) {
+ return fmt.Errorf("expected one ASN, but got %d", count)
+ }
+
+ result := res.GetPayload().Results[0]
+ d.Set("id", result.ID)
+ d.Set("asn", strconv.FormatInt(*result.Asn, 10))
+ d.Set("description", result.Description)
+ d.Set("tags", getTagListFromNestedTagList(result.Tags))
+ d.SetId(strconv.FormatInt(result.ID, 10))
+ return nil
+}
diff --git a/netbox/data_source_netbox_asn_test.go b/netbox/data_source_netbox_asn_test.go
new file mode 100644
index 00000000..d51cffc8
--- /dev/null
+++ b/netbox/data_source_netbox_asn_test.go
@@ -0,0 +1,78 @@
+package netbox
+
+import (
+ "fmt"
+ "regexp"
+ "testing"
+
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
+)
+
+func testAccNetboxAsnSetUp(testName string) string {
+ return fmt.Sprintf(`
+resource "netbox_rir" "test" {
+ name = "%[1]s"
+}
+
+resource "netbox_tag" "test" {
+ name = "%[1]s"
+}
+
+resource "netbox_asn" "test" {
+ asn = "123"
+ rir_id = netbox_rir.test.id
+ tags = [netbox_tag.test.slug]
+}`, testName)
+}
+
+const testAccNetboxAsnNoResult = `
+data "netbox_asn" "test" {
+ asn = "1337"
+}`
+
+func testAccNetboxAsnByAsn() string {
+ return fmt.Sprintf(`
+data "netbox_asn" "test" {
+ asn = "123"
+}`)
+}
+
+func testAccNetboxAsnByTag(testName string) string {
+ return fmt.Sprintf(`
+data "netbox_asn" "test" {
+ tag = "%[1]s"
+}`, testName)
+}
+
+func TestAccNetboxAsnDataSource_basic(t *testing.T) {
+ testName := testAccGetTestName("asn_ds_basic")
+ setUp := testAccNetboxAsnSetUp(testName)
+ resource.ParallelTest(t, resource.TestCase{
+ Providers: testAccProviders,
+ Steps: []resource.TestStep{
+ {
+ Config: setUp,
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr("netbox_asn.test", "asn", "123"),
+ ),
+ },
+ {
+ Config: setUp + testAccNetboxAsnNoResult,
+ ExpectError: regexp.MustCompile("expected one ASN, but got 0"),
+ },
+ {
+ Config: setUp + testAccNetboxAsnByAsn(),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttrPair("data.netbox_asn.test", "id", "netbox_asn.test", "id"),
+ ),
+ },
+ {
+ Config: setUp + testAccNetboxAsnByTag(testName),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttrPair("data.netbox_asn.test", "id", "netbox_asn.test", "id"),
+ resource.TestCheckResourceAttr("data.netbox_asn.test", "asn", "123"),
+ ),
+ },
+ },
+ })
+}
diff --git a/netbox/data_source_netbox_asns.go b/netbox/data_source_netbox_asns.go
new file mode 100644
index 00000000..551ba68a
--- /dev/null
+++ b/netbox/data_source_netbox_asns.go
@@ -0,0 +1,121 @@
+package netbox
+
+import (
+ "errors"
+ "fmt"
+
+ "github.com/fbreckle/go-netbox/netbox/client"
+ "github.com/fbreckle/go-netbox/netbox/client/ipam"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
+)
+
+func dataSourceNetboxAsns() *schema.Resource {
+ return &schema.Resource{
+ Read: dataSourceNetboxAsnsRead,
+ Description: `:meta:subcategory:IP Address Management (IPAM):`,
+ Schema: map[string]*schema.Schema{
+ "filter": {
+ Type: schema.TypeSet,
+ Optional: true,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "name": {
+ Type: schema.TypeString,
+ Required: true,
+ },
+ "value": {
+ Type: schema.TypeString,
+ Required: true,
+ },
+ },
+ },
+ },
+ "limit": {
+ Type: schema.TypeInt,
+ Optional: true,
+ ValidateDiagFunc: validation.ToDiagFunc(validation.IntAtLeast(1)),
+ Default: 0,
+ },
+ "asns": {
+ Type: schema.TypeList,
+ Computed: true,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "id": {
+ Type: schema.TypeInt,
+ Computed: true,
+ },
+ "asn": {
+ Type: schema.TypeInt,
+ Computed: true,
+ },
+ "rir_id": {
+ Type: schema.TypeInt,
+ Computed: true,
+ },
+ "tags": tagsSchemaRead,
+ },
+ },
+ },
+ },
+ }
+}
+
+func dataSourceNetboxAsnsRead(d *schema.ResourceData, m interface{}) error {
+ api := m.(*client.NetBoxAPI)
+
+ params := ipam.NewIpamAsnsListParams()
+
+ 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 "asn":
+ params.Asn = &vString
+ case "asn__gte":
+ params.AsnGte = &vString
+ case "asn__lte":
+ params.AsnLte = &vString
+ case "asn__n":
+ params.Asnn = &vString
+ default:
+ return fmt.Errorf("'%s' is not a supported filter parameter", k)
+ }
+ }
+ }
+
+ res, err := api.Ipam.IpamAsnsList(params, nil)
+ if err != nil {
+ return err
+ }
+
+ if *res.GetPayload().Count == int64(0) {
+ return errors.New("no result")
+ }
+
+ filteredAsns := res.GetPayload().Results
+
+ var s []map[string]interface{}
+ for _, v := range filteredAsns {
+ var mapping = make(map[string]interface{})
+
+ mapping["id"] = v.ID
+ mapping["asn"] = v.Asn
+ mapping["rir_id"] = v.Rir
+ mapping["tags"] = getTagListFromNestedTagList(v.Tags)
+
+ s = append(s, mapping)
+ }
+
+ d.SetId(resource.UniqueId())
+ return d.Set("asns", s)
+}
diff --git a/netbox/data_source_netbox_asns_test.go b/netbox/data_source_netbox_asns_test.go
new file mode 100644
index 00000000..4e076fc9
--- /dev/null
+++ b/netbox/data_source_netbox_asns_test.go
@@ -0,0 +1,104 @@
+package netbox
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
+)
+
+func testAccNetboxAsnsSetUp(testName string) string {
+ return fmt.Sprintf(`
+resource "netbox_rir" "test" {
+ name = "%[1]s"
+}
+
+resource "netbox_tag" "test" {
+ name = "%[1]s"
+}
+
+resource "netbox_asn" "test_1" {
+ asn = "123"
+ rir_id = netbox_rir.test.id
+ tags = [netbox_tag.test.slug]
+}
+
+resource "netbox_asn" "test_2" {
+ asn = "1234"
+ rir_id = netbox_rir.test.id
+ tags = [netbox_tag.test.slug]
+ }`, testName)
+}
+
+func testAccNetboxAsnsByAsn() string {
+ return fmt.Sprintf(`
+data "netbox_asns" "test" {
+ filter {
+ name = "asn"
+ value = "123"
+ }
+}`)
+}
+
+func testAccNetboxAsnsByAsnN() string {
+ return fmt.Sprintf(`
+data "netbox_asns" "test" {
+ filter {
+ name = "asn__n"
+ value = "123"
+ }
+}`)
+}
+
+func testAccNetboxAsnsByRange(testName string) string {
+ return fmt.Sprintf(`
+data "netbox_asns" "test" {
+ filter {
+ name = "asn__gte"
+ value = "100"
+ }
+
+ filter {
+ name = "asn__lte"
+ value = "2000"
+ }
+}`)
+}
+
+func TestAccNetboxAsnsDataSource_basic(t *testing.T) {
+ testName := testAccGetTestName("asns_ds_basic")
+ setUp := testAccNetboxAsnsSetUp(testName)
+ resource.ParallelTest(t, resource.TestCase{
+ Providers: testAccProviders,
+ Steps: []resource.TestStep{
+ {
+ Config: setUp,
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr("netbox_asn.test_1", "asn", "123"),
+ ),
+ },
+ {
+ Config: setUp + testAccNetboxAsnsByAsn(),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr("data.netbox_asns.test", "asns.#", "1"),
+ resource.TestCheckResourceAttrPair("data.netbox_asns.test", "asns.0.id", "netbox_asn.test_1", "id"),
+ ),
+ },
+ {
+ Config: setUp + testAccNetboxAsnsByAsnN(),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr("data.netbox_asns.test", "asns.#", "1"),
+ resource.TestCheckResourceAttrPair("data.netbox_asns.test", "asns.0.id", "netbox_asn.test_2", "id"),
+ ),
+ },
+ {
+ Config: setUp + testAccNetboxAsnsByRange(testName),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr("data.netbox_asns.test", "asns.#", "2"),
+ resource.TestCheckResourceAttrPair("data.netbox_asns.test", "asns.0.id", "netbox_asn.test_1", "id"),
+ resource.TestCheckResourceAttrPair("data.netbox_asns.test", "asns.1.id", "netbox_asn.test_2", "id"),
+ ),
+ },
+ },
+ })
+}
diff --git a/netbox/data_source_netbox_cluster.go b/netbox/data_source_netbox_cluster.go
index 332891f4..563d31ff 100644
--- a/netbox/data_source_netbox_cluster.go
+++ b/netbox/data_source_netbox_cluster.go
@@ -18,10 +18,23 @@ func dataSourceNetboxCluster() *schema.Resource {
Type: schema.TypeInt,
Computed: true,
},
+ "site_id": &schema.Schema{
+ Type: schema.TypeInt,
+ Computed: true,
+ },
"name": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
+ "cluster_type_id": &schema.Schema{
+ Type: schema.TypeInt,
+ Computed: true,
+ },
+ "cluster_group_id": &schema.Schema{
+ Type: schema.TypeInt,
+ Computed: true,
+ },
+ tagsKey: tagsSchemaRead,
},
}
}
@@ -50,5 +63,20 @@ func dataSourceNetboxClusterRead(d *schema.ResourceData, m interface{}) error {
d.Set("cluster_id", result.ID)
d.SetId(strconv.FormatInt(result.ID, 10))
d.Set("name", result.Name)
+ d.Set("cluster_type_id", result.Type.ID)
+
+ if result.Group != nil {
+ d.Set("cluster_group_id", result.Group.ID)
+ } else {
+ d.Set("cluster_group_id", nil)
+ }
+
+ if result.Site != nil {
+ d.Set("site_id", result.Site.ID)
+ } else {
+ d.Set("site_id", nil)
+ }
+
+ d.Set(tagsKey, getTagListFromNestedTagList(result.Tags))
return nil
}
diff --git a/netbox/data_source_netbox_cluster_test.go b/netbox/data_source_netbox_cluster_test.go
index 9607072b..049d046c 100644
--- a/netbox/data_source_netbox_cluster_test.go
+++ b/netbox/data_source_netbox_cluster_test.go
@@ -16,20 +16,43 @@ func TestAccNetboxClusterDataSource_basic(t *testing.T) {
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(`
+resource "netbox_tag" "test" {
+ name = "%[1]s"
+}
+
resource "netbox_cluster_type" "test" {
name = "%[1]s"
}
+
+resource "netbox_cluster_group" "test" {
+ name = "%[1]s"
+}
+
+resource "netbox_site" "test" {
+ name = "%[1]s"
+ status = "active"
+}
+
resource "netbox_cluster" "test" {
name = "%[1]s"
cluster_type_id = netbox_cluster_type.test.id
+ cluster_group_id = netbox_cluster_group.test.id
+ site_id = netbox_site.test.id
+ tags = [netbox_tag.test.name]
}
+
data "netbox_cluster" "test" {
- depends_on = [netbox_cluster.test]
+ depends_on = [netbox_cluster.test, netbox_cluster_group.test]
name = "%[1]s"
-}`, testName),
+}
+`, testName),
Check: resource.ComposeTestCheckFunc(
- resource.TestCheckResourceAttrPair("data.netbox_cluster.test", "cluster_id", "netbox_cluster.test", "id"),
- resource.TestCheckResourceAttrPair("data.netbox_cluster.test", "id", "netbox_cluster.test", "id"),
+ resource.TestCheckResourceAttr("data.netbox_cluster.test", "name", testName),
+ resource.TestCheckResourceAttrPair("data.netbox_cluster.test", "cluster_type_id", "netbox_cluster_type.test", "id"),
+ resource.TestCheckResourceAttrPair("data.netbox_cluster.test", "cluster_group_id", "netbox_cluster_group.test", "id"),
+ resource.TestCheckResourceAttrPair("data.netbox_cluster.test", "site_id", "netbox_site.test", "id"),
+ resource.TestCheckResourceAttr("data.netbox_cluster.test", "tags.#", "1"),
+ resource.TestCheckResourceAttr("data.netbox_cluster.test", "tags.0", testName),
),
},
},
diff --git a/netbox/data_source_netbox_device_role.go b/netbox/data_source_netbox_device_role.go
index 9838984c..685f4921 100644
--- a/netbox/data_source_netbox_device_role.go
+++ b/netbox/data_source_netbox_device_role.go
@@ -26,6 +26,7 @@ func dataSourceNetboxDeviceRole() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
+ tagsKey: tagsSchemaRead,
},
}
}
@@ -55,5 +56,6 @@ func dataSourceNetboxDeviceRoleRead(d *schema.ResourceData, m interface{}) error
d.Set("name", result.Name)
d.Set("slug", result.Slug)
d.Set("color_hex", result.Color)
+ d.Set(tagsKey, getTagListFromNestedTagList(result.Tags))
return nil
}
diff --git a/netbox/data_source_netbox_device_role_test.go b/netbox/data_source_netbox_device_role_test.go
index b586d377..4ad60f9e 100644
--- a/netbox/data_source_netbox_device_role_test.go
+++ b/netbox/data_source_netbox_device_role_test.go
@@ -16,16 +16,24 @@ func TestAccNetboxDeviceRoleDataSource_basic(t *testing.T) {
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(`
+resource "netbox_tag" "test" {
+ name = "%[1]s"
+}
+
resource "netbox_device_role" "test" {
name = "%[1]s"
color_hex = "123456"
+ tags = [netbox_tag.test.name]
}
+
data "netbox_device_role" "test" {
depends_on = [netbox_device_role.test]
name = "%[1]s"
}`, testName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrPair("data.netbox_device_role.test", "id", "netbox_device_role.test", "id"),
+ resource.TestCheckResourceAttr("data.netbox_device_role.test", "tags.#", "1"),
+ resource.TestCheckResourceAttr("data.netbox_device_role.test", "tags.0", testName),
),
},
},
diff --git a/netbox/data_source_netbox_devices_test.go b/netbox/data_source_netbox_devices_test.go
index e4c6962b..13945643 100644
--- a/netbox/data_source_netbox_devices_test.go
+++ b/netbox/data_source_netbox_devices_test.go
@@ -31,8 +31,10 @@ func TestAccNetboxDevicesDataSource_basic(t *testing.T) {
resource.TestCheckResourceAttrPair("data.netbox_devices.test", "devices.0.role_id", "netbox_device_role.test", "id"),
resource.TestCheckResourceAttrPair("data.netbox_devices.test", "devices.0.device_type_id", "netbox_device_type.test", "id"),
resource.TestCheckResourceAttrPair("data.netbox_devices.test", "devices.0.site_id", "netbox_site.test", "id"),
+ resource.TestCheckResourceAttrPair("data.netbox_devices.test", "devices.0.platform_id", "netbox_platform.test", "id"),
resource.TestCheckResourceAttrPair("data.netbox_devices.test", "devices.0.location_id", "netbox_location.test", "id"),
resource.TestCheckResourceAttr("data.netbox_devices.test", "devices.0.serial", "ABCDEF0"),
+ resource.TestCheckResourceAttr("data.netbox_devices.test", "devices.0.status", "staged"),
),
},
{
@@ -85,8 +87,10 @@ resource "netbox_device" "test0" {
role_id = netbox_device_role.test.id
device_type_id = netbox_device_type.test.id
site_id = netbox_site.test.id
+ platform_id = netbox_platform.test.id
location_id = netbox_location.test.id
serial = "ABCDEF0"
+ status = "staged"
}
resource "netbox_device" "test1" {
@@ -96,6 +100,7 @@ resource "netbox_device" "test1" {
role_id = netbox_device_role.test.id
device_type_id = netbox_device_type.test.id
site_id = netbox_site.test.id
+ platform_id = netbox_platform.test.id
location_id = netbox_location.test.id
serial = "ABCDEF1"
}
@@ -107,6 +112,7 @@ resource "netbox_device" "test2" {
role_id = netbox_device_role.test.id
device_type_id = netbox_device_type.test.id
site_id = netbox_site.test.id
+ platform_id = netbox_platform.test.id
location_id = netbox_location.test.id
serial = "ABCDEF2"
}
@@ -118,6 +124,7 @@ resource "netbox_device" "test3" {
role_id = netbox_device_role.test.id
device_type_id = netbox_device_type.test.id
site_id = netbox_site.test.id
+ platform_id = netbox_platform.test.id
location_id = netbox_location.test.id
serial = "ABCDEF3"
}
diff --git a/netbox/data_source_netbox_prefix.go b/netbox/data_source_netbox_prefix.go
index 69916be3..e2496b99 100644
--- a/netbox/data_source_netbox_prefix.go
+++ b/netbox/data_source_netbox_prefix.go
@@ -20,14 +20,61 @@ func dataSourceNetboxPrefix() *schema.Resource {
Computed: true,
},
"cidr": {
+ Type: schema.TypeString,
+ Optional: true,
+ Deprecated: "The `cidr` parameter is deprecated in favor of the canonical `prefix` attribute.",
+ ConflictsWith: []string{"prefix"},
+ ValidateFunc: validation.IsCIDR,
+ AtLeastOneOf: []string{"description", "prefix", "vlan_vid", "vrf_id", "vlan_id", "cidr", "tag"},
+ },
+ "description": {
Type: schema.TypeString,
Optional: true,
- ValidateFunc: validation.IsCIDR,
+ Computed: true,
+ AtLeastOneOf: []string{"description", "prefix", "vlan_vid", "vrf_id", "vlan_id", "cidr", "tag"},
+ Description: "Description to include in the data source filter.",
+ },
+ "prefix": {
+ Type: schema.TypeString,
+ Optional: true,
+ ValidateFunc: validation.IsCIDR,
+ ConflictsWith: []string{"cidr"},
+ AtLeastOneOf: []string{"description", "prefix", "vlan_vid", "vrf_id", "vlan_id", "cidr", "tag"},
+ },
+ "vlan_vid": {
+ Type: schema.TypeFloat,
+ Optional: true,
+ AtLeastOneOf: []string{"description", "prefix", "vlan_vid", "vrf_id", "vlan_id", "cidr", "tag"},
+ ValidateFunc: validation.FloatBetween(1, 4094),
},
"vrf_id": {
- Type: schema.TypeInt,
+ Type: schema.TypeInt,
+ Optional: true,
+ AtLeastOneOf: []string{"description", "prefix", "vlan_vid", "vrf_id", "vlan_id", "cidr", "tag"},
+ },
+ "vlan_id": {
+ Type: schema.TypeInt,
+ Optional: true,
+ AtLeastOneOf: []string{"description", "prefix", "vlan_vid", "vrf_id", "vlan_id", "cidr", "tag"},
+ },
+ "tag": {
+ Type: schema.TypeString,
+ Optional: true,
+ AtLeastOneOf: []string{"description", "prefix", "vlan_vid", "vrf_id", "vlan_id", "cidr", "tag"},
+ Description: "Tag to include in the data source filter (must match the tag's slug).",
+ },
+ "tag__n": {
+ Type: schema.TypeString,
Optional: true,
+ Description: `Tag to exclude from the data source filter (must match the tag's slug).
+Refer to [Netbox's documentation](https://demo.netbox.dev/static/docs/rest-api/filtering/#lookup-expressions)
+for more information on available lookup expressions.`,
+ },
+ "status": {
+ Type: schema.TypeString,
+ Computed: true,
},
+ "tags": tagsSchemaRead,
},
}
}
@@ -40,15 +87,39 @@ func dataSourceNetboxPrefixRead(d *schema.ResourceData, m interface{}) error {
limit := int64(2) // Limit of 2 is enough
params.Limit = &limit
+ // note: cidr is deprecated in favor of prefix
if cidr, ok := d.Get("cidr").(string); ok && cidr != "" {
params.Prefix = &cidr
}
+ if description, ok := d.Get("description").(string); ok && description != "" {
+ params.Description = &description
+ }
+
+ if prefix, ok := d.Get("prefix").(string); ok && prefix != "" {
+ params.Prefix = &prefix
+ }
+
if vrfId, ok := d.Get("vrf_id").(int); ok && vrfId != 0 {
// Note that vrf_id is a string pointer in the netbox filter, but we use a number in the provider
params.VrfID = strToPtr(strconv.Itoa(vrfId))
}
+ if vlanId, ok := d.Get("vlan_id").(int); ok && vlanId != 0 {
+ // Note that vlan_id is a string pointer in the netbox filter, but we use a number in the provider
+ params.VlanID = strToPtr(strconv.Itoa(vlanId))
+ }
+
+ if vlanVid, ok := d.Get("vlan_vid").(float64); ok && vlanVid != 0 {
+ params.VlanVid = &vlanVid
+ }
+ if tag, ok := d.Get("tag").(string); ok && tag != "" {
+ params.Tag = &tag
+ }
+ if tagn, ok := d.Get("tag__n").(string); ok && tagn != "" {
+ params.Tagn = &tagn
+ }
+
res, err := api.Ipam.IpamPrefixesList(params, nil)
if err != nil {
return err
@@ -60,6 +131,20 @@ func dataSourceNetboxPrefixRead(d *schema.ResourceData, m interface{}) error {
result := res.GetPayload().Results[0]
d.Set("id", result.ID)
+ d.Set("cidr", result.Prefix)
+ d.Set("prefix", result.Prefix)
+ d.Set("status", result.Status.Value)
+ d.Set("description", result.Description)
+ d.Set("tags", getTagListFromNestedTagList(result.Tags))
+
+ if result.Vrf != nil {
+ d.Set("vrf_id", result.Vrf.ID)
+ }
+ if result.Vlan != nil {
+ d.Set("vlan_vid", result.Vlan.Vid)
+ d.Set("vlan_id", result.Vlan.ID)
+ }
+
d.SetId(strconv.FormatInt(result.ID, 10))
return nil
}
diff --git a/netbox/data_source_netbox_prefix_test.go b/netbox/data_source_netbox_prefix_test.go
index 6e011e75..0c6219ce 100644
--- a/netbox/data_source_netbox_prefix_test.go
+++ b/netbox/data_source_netbox_prefix_test.go
@@ -9,21 +9,38 @@ import (
func TestAccNetboxPrefixDataSource_basic(t *testing.T) {
- testPrefixes := []string{"10.0.0.0/24", "10.0.1.0/24"}
+ testPrefixes := []string{"10.0.0.0/24", "10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24", "10.0.4.0/24"}
testSlug := "prefix_ds_basic"
+ testVlanVids := []int{4090, 4091}
testName := testAccGetTestName(testSlug)
resource.ParallelTest(t, resource.TestCase{
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(`
-resource "netbox_prefix" "by_cidr" {
+resource "netbox_prefix" "by_prefix" {
prefix = "%[2]s"
status = "active"
}
+resource "netbox_prefix" "by_description" {
+ prefix = "%[6]s"
+ status = "active"
+ description = "%[6]s_description_test_id"
+}
+
resource "netbox_vrf" "test" {
- name = "%[1]s"
+ name = "%[1]s_vrf"
+}
+
+resource "netbox_vlan" "test_id" {
+ name = "%[1]s_vlan_test_id"
+ vid = %[7]d
+}
+
+resource "netbox_vlan" "test_vid" {
+ name = "%[1]s_vlan_test_vid"
+ vid = %[8]d
}
resource "netbox_prefix" "by_vrf" {
@@ -32,8 +49,30 @@ resource "netbox_prefix" "by_vrf" {
vrf_id = netbox_vrf.test.id
}
+resource "netbox_prefix" "by_vlan_id" {
+ prefix = "%[4]s"
+ status = "active"
+ vlan_id = netbox_vlan.test_id.id
+}
+
+resource "netbox_prefix" "by_vlan_vid" {
+ prefix = "%[5]s"
+ status = "active"
+ vlan_id = netbox_vlan.test_vid.id
+}
+
+data "netbox_prefix" "by_prefix" {
+ depends_on = [netbox_prefix.by_prefix]
+ prefix = "%[2]s"
+}
+
+data "netbox_prefix" "by_description" {
+ depends_on = [netbox_prefix.by_description]
+ description = netbox_prefix.by_description.description
+}
+
data "netbox_prefix" "by_cidr" {
- depends_on = [netbox_prefix.by_cidr]
+ depends_on = [netbox_prefix.by_prefix]
cidr = "%[2]s"
}
@@ -41,12 +80,25 @@ data "netbox_prefix" "by_vrf_id" {
depends_on = [netbox_prefix.by_vrf]
vrf_id = netbox_vrf.test.id
}
-`, testName, testPrefixes[0], testPrefixes[1]),
+
+data "netbox_prefix" "by_vlan_id" {
+ depends_on = [netbox_prefix.by_vlan_id]
+ vlan_id = netbox_vlan.test_id.id
+}
+
+data "netbox_prefix" "by_vlan_vid" {
+ depends_on = [netbox_prefix.by_vlan_vid]
+ vlan_vid = %[8]d
+}
+`, testName, testPrefixes[0], testPrefixes[1], testPrefixes[2], testPrefixes[3], testPrefixes[4], testVlanVids[0], testVlanVids[1]),
Check: resource.ComposeTestCheckFunc(
- resource.TestCheckResourceAttrPair("data.netbox_prefix.by_cidr", "id", "netbox_prefix.by_cidr", "id"),
+ resource.TestCheckResourceAttrPair("data.netbox_prefix.by_prefix", "id", "netbox_prefix.by_prefix", "id"),
+ resource.TestCheckResourceAttrPair("data.netbox_prefix.by_description", "id", "netbox_prefix.by_description", "id"),
+ resource.TestCheckResourceAttrPair("data.netbox_prefix.by_cidr", "id", "netbox_prefix.by_prefix", "id"),
resource.TestCheckResourceAttrPair("data.netbox_prefix.by_vrf_id", "id", "netbox_prefix.by_vrf", "id"),
+ resource.TestCheckResourceAttrPair("data.netbox_prefix.by_vlan_id", "id", "netbox_prefix.by_vlan_id", "id"),
+ resource.TestCheckResourceAttrPair("data.netbox_prefix.by_vlan_vid", "id", "netbox_prefix.by_vlan_vid", "id"),
),
- ExpectNonEmptyPlan: false,
},
},
})
diff --git a/netbox/data_source_netbox_prefixes.go b/netbox/data_source_netbox_prefixes.go
new file mode 100644
index 00000000..8d0fd3f6
--- /dev/null
+++ b/netbox/data_source_netbox_prefixes.go
@@ -0,0 +1,138 @@
+package netbox
+
+import (
+ "errors"
+ "fmt"
+
+ "github.com/fbreckle/go-netbox/netbox/client"
+ "github.com/fbreckle/go-netbox/netbox/client/ipam"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
+)
+
+func dataSourceNetboxPrefixes() *schema.Resource {
+ return &schema.Resource{
+ Read: dataSourceNetboxPrefixesRead,
+ Description: `:meta:subcategory:IP Address Management (IPAM):`,
+ Schema: map[string]*schema.Schema{
+ "filter": {
+ Type: schema.TypeSet,
+ Optional: true,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "name": {
+ Type: schema.TypeString,
+ Required: true,
+ },
+ "value": {
+ Type: schema.TypeString,
+ Required: true,
+ },
+ },
+ },
+ },
+ "limit": {
+ Type: schema.TypeInt,
+ Optional: true,
+ ValidateDiagFunc: validation.ToDiagFunc(validation.IntAtLeast(1)),
+ Default: 0,
+ },
+ "prefixes": {
+ Type: schema.TypeList,
+ Computed: true,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "id": {
+ Type: schema.TypeInt,
+ Computed: true,
+ },
+ "prefix": {
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ "vlan_vid": {
+ Type: schema.TypeFloat,
+ Computed: true,
+ },
+ "vrf_id": {
+ Type: schema.TypeInt,
+ Computed: true,
+ },
+ "vlan_id": {
+ Type: schema.TypeInt,
+ Computed: true,
+ },
+ "status": {
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ },
+ },
+ },
+ },
+ }
+}
+
+func dataSourceNetboxPrefixesRead(d *schema.ResourceData, m interface{}) error {
+ api := m.(*client.NetBoxAPI)
+
+ params := ipam.NewIpamPrefixesListParams()
+
+ 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 "prefix":
+ params.Prefix = &vString
+ case "vlan_vid":
+ params.VlanVid = v.(*float64)
+ case "vrf_id":
+ params.VrfID = &vString
+ case "vlan_id":
+ params.VlanID = &vString
+ default:
+ return fmt.Errorf("'%s' is not a supported filter parameter", k)
+ }
+ }
+ }
+
+ res, err := api.Ipam.IpamPrefixesList(params, nil)
+ if err != nil {
+ return err
+ }
+
+ if *res.GetPayload().Count == int64(0) {
+ return errors.New("no result")
+ }
+
+ filteredPrefixes := res.GetPayload().Results
+
+ var s []map[string]interface{}
+ for _, v := range filteredPrefixes {
+ var mapping = make(map[string]interface{})
+
+ mapping["id"] = v.ID
+ mapping["prefix"] = v.Prefix
+ if v.Vlan != nil {
+ mapping["vlan_vid"] = v.Vlan.Vid
+ mapping["vlan_id"] = v.Vlan.ID
+ }
+ if v.Vrf != nil {
+ mapping["vrf_id"] = v.Vrf.ID
+ }
+ mapping["status"] = v.Status.Value
+
+ s = append(s, mapping)
+ }
+
+ d.SetId(resource.UniqueId())
+ return d.Set("prefixes", s)
+}
diff --git a/netbox/data_source_netbox_prefixes_test.go b/netbox/data_source_netbox_prefixes_test.go
new file mode 100644
index 00000000..d8bbdb86
--- /dev/null
+++ b/netbox/data_source_netbox_prefixes_test.go
@@ -0,0 +1,77 @@
+package netbox
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
+)
+
+func TestAccNetboxPrefixesDataSource_basic(t *testing.T) {
+
+ testPrefixes := []string{"10.0.4.0/24", "10.0.5.0/24", "10.0.6.0/24"}
+ testSlug := "prefixes_ds_basic"
+ testVlanVids := []int{4093, 4094}
+ testName := testAccGetTestName(testSlug)
+ resource.ParallelTest(t, resource.TestCase{
+ Providers: testAccProviders,
+ Steps: []resource.TestStep{
+ {
+ Config: fmt.Sprintf(`
+resource "netbox_prefix" "test_prefix1" {
+ prefix = "%[2]s"
+ status = "active"
+ vrf_id = netbox_vrf.test_vrf.id
+ vlan_id = netbox_vlan.test_vlan1.id
+}
+
+resource "netbox_prefix" "test_prefix2" {
+ prefix = "%[3]s"
+ status = "active"
+ vrf_id = netbox_vrf.test_vrf.id
+ vlan_id = netbox_vlan.test_vlan2.id
+}
+
+resource "netbox_prefix" "without_vrf_and_vlan" {
+ prefix = "%[4]s"
+ status = "active"
+}
+
+resource "netbox_vrf" "test_vrf" {
+ name = "%[1]s_test_vrf"
+}
+
+resource "netbox_vlan" "test_vlan1" {
+ name = "%[1]s_vlan1"
+ vid = %[5]d
+}
+
+resource "netbox_vlan" "test_vlan2" {
+ name = "%[1]s_vlan2"
+ vid = %[6]d
+}
+
+data "netbox_prefixes" "by_vrf" {
+ depends_on = [netbox_prefix.test_prefix1]
+ filter {
+ name = "vrf_id"
+ value = netbox_vrf.test_vrf.id
+ }
+}
+
+data "netbox_prefixes" "find_prefix_without_vrf_and_vlan" {
+ depends_on = [netbox_prefix.without_vrf_and_vlan]
+ filter {
+ name = "prefix"
+ value = netbox_prefix.without_vrf_and_vlan.prefix
+ }
+}
+`, testName, testPrefixes[0], testPrefixes[1], testPrefixes[2], testVlanVids[0], testVlanVids[1]),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr("data.netbox_prefixes.by_vrf", "prefixes.#", "2"),
+ resource.TestCheckResourceAttrPair("data.netbox_prefixes.by_vrf", "prefixes.1.vlan_vid", "netbox_vlan.test_vlan2", "vid"),
+ ),
+ },
+ },
+ })
+}
diff --git a/netbox/data_source_netbox_tenant.go b/netbox/data_source_netbox_tenant.go
index ecc9cb92..4f2ac515 100644
--- a/netbox/data_source_netbox_tenant.go
+++ b/netbox/data_source_netbox_tenant.go
@@ -14,22 +14,26 @@ func dataSourceNetboxTenant() *schema.Resource {
Read: dataSourceNetboxTenantRead,
Description: `:meta:subcategory:Tenancy:`,
Schema: map[string]*schema.Schema{
- "name": &schema.Schema{
+ "name": {
Type: schema.TypeString,
Computed: true,
Optional: true,
AtLeastOneOf: []string{"name", "slug"},
},
- "slug": &schema.Schema{
+ "slug": {
Type: schema.TypeString,
Optional: true,
Computed: true,
AtLeastOneOf: []string{"name", "slug"},
},
- "group_id": &schema.Schema{
+ "group_id": {
Type: schema.TypeInt,
Computed: true,
},
+ "description": &schema.Schema{
+ Type: schema.TypeString,
+ Optional: true,
+ },
},
}
}
@@ -64,6 +68,7 @@ func dataSourceNetboxTenantRead(d *schema.ResourceData, m interface{}) error {
d.SetId(strconv.FormatInt(result.ID, 10))
d.Set("name", result.Name)
d.Set("slug", result.Slug)
+ d.Set("description", result.Description)
if result.Group != nil {
d.Set("group_id", result.Group.ID)
}
diff --git a/netbox/data_source_netbox_tenant_test.go b/netbox/data_source_netbox_tenant_test.go
index 901f88ef..582a0e8d 100644
--- a/netbox/data_source_netbox_tenant_test.go
+++ b/netbox/data_source_netbox_tenant_test.go
@@ -30,15 +30,23 @@ data "netbox_tenant" "by_slug" {
slug = "%[1]s"
}
+data "netbox_tenant" "by_description" {
+ depends_on = [netbox_tenant.test]
+ name = "%[1]s"
+ description = "%[1]s"
+}
+
data "netbox_tenant" "by_both" {
depends_on = [netbox_tenant.test]
name = "%[1]s"
slug = "%[1]s"
+ description = "%[1]s"
}
`, testName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrPair("data.netbox_tenant.by_name", "id", "netbox_tenant.test", "id"),
resource.TestCheckResourceAttrPair("data.netbox_tenant.by_slug", "id", "netbox_tenant.test", "id"),
+ resource.TestCheckResourceAttrPair("data.netbox_tenant.by_description", "id", "netbox_tenant.test", "id"),
resource.TestCheckResourceAttrPair("data.netbox_tenant.by_both", "id", "netbox_tenant.test", "id"),
),
},
diff --git a/netbox/data_source_netbox_vlan.go b/netbox/data_source_netbox_vlan.go
index 2f4596c1..f0df1b0b 100644
--- a/netbox/data_source_netbox_vlan.go
+++ b/netbox/data_source_netbox_vlan.go
@@ -18,21 +18,25 @@ func dataSourceNetboxVlan() *schema.Resource {
"vid": {
Type: schema.TypeInt,
Optional: true,
- AtLeastOneOf: []string{"name", "vid"},
ValidateFunc: validation.IntBetween(1, 4094),
},
"name": {
- Type: schema.TypeString,
- Optional: true,
- AtLeastOneOf: []string{"name", "vid"},
+ Type: schema.TypeString,
+ Optional: true,
},
"description": {
Type: schema.TypeString,
Computed: true,
},
+ "group_id": {
+ Type: schema.TypeInt,
+ Computed: true,
+ Optional: true,
+ },
"role": {
Type: schema.TypeInt,
Computed: true,
+ Optional: true,
},
"site": {
Type: schema.TypeInt,
@@ -45,6 +49,7 @@ func dataSourceNetboxVlan() *schema.Resource {
"tenant": {
Type: schema.TypeInt,
Computed: true,
+ Optional: true,
},
},
}
@@ -61,6 +66,15 @@ func dataSourceNetboxVlanRead(d *schema.ResourceData, m interface{}) error {
if vid, ok := d.Get("vid").(int); ok && vid != 0 {
params.Vid = strToPtr(strconv.Itoa(vid))
}
+ if groupID, ok := d.Get("group_id").(int); ok && groupID != 0 {
+ params.GroupID = strToPtr(strconv.Itoa(groupID))
+ }
+ if roleID, ok := d.Get("role").(int); ok && roleID != 0 {
+ params.RoleID = strToPtr(strconv.Itoa(roleID))
+ }
+ if tenantID, ok := d.Get("tenant").(int); ok && tenantID != 0 {
+ params.TenantID = strToPtr(strconv.Itoa(tenantID))
+ }
res, err := api.Ipam.IpamVlansList(params, nil)
if err != nil {
@@ -78,6 +92,9 @@ func dataSourceNetboxVlanRead(d *schema.ResourceData, m interface{}) error {
d.Set("status", vlan.Status.Value)
d.Set("description", vlan.Description)
+ if vlan.Group != nil {
+ d.Set("group_id", vlan.Group.ID)
+ }
if vlan.Role != nil {
d.Set("role", vlan.Role.ID)
}
diff --git a/netbox/data_source_netbox_vlan_test.go b/netbox/data_source_netbox_vlan_test.go
index cae561fa..3db49b76 100644
--- a/netbox/data_source_netbox_vlan_test.go
+++ b/netbox/data_source_netbox_vlan_test.go
@@ -12,6 +12,7 @@ func TestAccNetboxVlanDataSource_basic(t *testing.T) {
testVid := 4092
testName := testAccGetTestName("vlan")
setUp := testAccNetboxVlanSetUp(testVid, testName)
+ extendedSetUp := testAccNetboxVlanSetUpMore(testVid, testVid-1, testName)
resource.ParallelTest(t, resource.TestCase{
Providers: testAccProviders,
Steps: []resource.TestStep{
@@ -30,29 +31,82 @@ func TestAccNetboxVlanDataSource_basic(t *testing.T) {
},
{
Config: setUp + testAccNetboxVlanDataByVid(testVid),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttrPair("data.netbox_vlan.test", "id", "netbox_vlan.test", "id"),
+ ),
+ },
+
+ {
+ Config: setUp + extendedSetUp + testAccNetboxVlanDataByNameAndRole(testName),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttrPair("data.netbox_vlan.test", "id", "netbox_vlan.test", "id"),
+ ),
+ },
+ {
+ Config: setUp + extendedSetUp + testAccNetboxVlanDataByVidAndTenant(testVid),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrPair("data.netbox_vlan.test", "id", "netbox_vlan.test", "id"),
resource.TestCheckResourceAttr("data.netbox_vlan.test", "name", testName),
resource.TestCheckResourceAttr("data.netbox_vlan.test", "status", "active"),
resource.TestCheckResourceAttr("data.netbox_vlan.test", "description", "Test"),
+ resource.TestCheckResourceAttrPair("data.netbox_vlan.test", "role", "netbox_ipam_role.test", "id"),
+ resource.TestCheckResourceAttrPair("data.netbox_vlan.test", "site", "netbox_site.test", "id"),
+ resource.TestCheckResourceAttrPair("data.netbox_vlan.test", "tenant", "netbox_tenant.test", "id"),
),
},
+ {
+ Config: setUp + extendedSetUp + testAccNetboxVlanDataByName(testName),
+ ExpectError: regexp.MustCompile("expected one device type, but got 2"),
+ },
+ {
+ Config: setUp + extendedSetUp + testAccNetboxVlanDataByVid(testVid),
+ ExpectError: regexp.MustCompile("expected one device type, but got 2"),
+ },
},
})
}
func testAccNetboxVlanSetUp(testVid int, testName string) string {
return fmt.Sprintf(`
+resource "netbox_ipam_role" "test" {
+ name = "%[2]s"
+}
+
+resource "netbox_site" "test" {
+ name = "%[2]s"
+}
+
+resource "netbox_tenant" "test" {
+ name = "%[2]s"
+}
+
resource "netbox_vlan" "test" {
vid = %[1]d
name = "%[2]s"
- status = "active"
description = "Test"
+ role_id = netbox_ipam_role.test.id
+ site_id = netbox_site.test.id
+ status = "active"
tags = []
+ tenant_id = netbox_tenant.test.id
}
`, testVid, testName)
}
+func testAccNetboxVlanSetUpMore(testVid int, anotherVid int, testName string) string {
+ return fmt.Sprintf(`
+resource "netbox_vlan" "same_name" {
+ vid = %[1]d
+ name = "%[3]s"
+}
+
+resource "netbox_vlan" "not_same" {
+ vid = %[2]d
+ name = "%[3]s_unique"
+}
+`, testVid, anotherVid, testName)
+}
+
const testAccNetboxVlanDataNoResult = `
data "netbox_vlan" "no_result" {
name = "_no_result_"
@@ -71,3 +125,19 @@ data "netbox_vlan" "test" {
vid = "%[1]d"
}`, testVid)
}
+
+func testAccNetboxVlanDataByNameAndRole(testName string) string {
+ return fmt.Sprintf(`
+data "netbox_vlan" "test" {
+ name = "%[1]s"
+ role = netbox_ipam_role.test.id
+}`, testName)
+}
+
+func testAccNetboxVlanDataByVidAndTenant(testVid int) string {
+ return fmt.Sprintf(`
+data "netbox_vlan" "test" {
+ vid = "%[1]d"
+ tenant = netbox_tenant.test.id
+}`, testVid)
+}
diff --git a/netbox/provider.go b/netbox/provider.go
index 2dd80595..15108f4c 100644
--- a/netbox/provider.go
+++ b/netbox/provider.go
@@ -62,7 +62,11 @@ func Provider() *schema.Provider {
"netbox_virtual_machine": resourceNetboxVirtualMachine(),
"netbox_cluster_type": resourceNetboxClusterType(),
"netbox_cluster": resourceNetboxCluster(),
+ "netbox_contact": resourceNetboxContact(),
+ "netbox_contact_assignment": resourceNetboxContactAssignment(),
+ "netbox_contact_role": resourceNetboxContactRole(),
"netbox_device": resourceNetboxDevice(),
+ "netbox_device_interface": resourceNetboxDeviceInterface(),
"netbox_device_type": resourceNetboxDeviceType(),
"netbox_manufacturer": resourceNetboxManufacturer(),
"netbox_tenant": resourceNetboxTenant(),
@@ -97,6 +101,8 @@ func Provider() *schema.Provider {
"netbox_site_group": resourceNetboxSiteGroup(),
},
DataSourcesMap: map[string]*schema.Resource{
+ "netbox_asn": dataSourceNetboxAsn(),
+ "netbox_asns": dataSourceNetboxAsns(),
"netbox_cluster": dataSourceNetboxCluster(),
"netbox_cluster_group": dataSourceNetboxClusterGroup(),
"netbox_cluster_type": dataSourceNetboxClusterType(),
@@ -106,6 +112,7 @@ func Provider() *schema.Provider {
"netbox_vrf": dataSourceNetboxVrf(),
"netbox_platform": dataSourceNetboxPlatform(),
"netbox_prefix": dataSourceNetboxPrefix(),
+ "netbox_prefixes": dataSourceNetboxPrefixes(),
"netbox_devices": dataSourceNetboxDevices(),
"netbox_device_role": dataSourceNetboxDeviceRole(),
"netbox_device_type": dataSourceNetboxDeviceType(),
@@ -193,7 +200,7 @@ func providerConfigure(ctx context.Context, data *schema.ResourceData) (interfac
netboxVersion := res.GetPayload().(map[string]interface{})["netbox-version"].(string)
- supportedVersions := []string{"3.3.0", "3.3.1", "3.3.2", "3.3.3", "3.3.4"}
+ supportedVersions := []string{"3.3.0", "3.3.1", "3.3.2", "3.3.3", "3.3.4", "3.3.5", "3.3.6", "3.3.7"}
if !slices.Contains(supportedVersions, netboxVersion) {
diff --git a/netbox/provider_test.go b/netbox/provider_test.go
index e5a8df1f..1ac7f3ed 100644
--- a/netbox/provider_test.go
+++ b/netbox/provider_test.go
@@ -37,7 +37,7 @@ func testAccGetTestToken() string {
func testAccPreCheck(t *testing.T) {
if v := os.Getenv("NETBOX_SERVER_URL"); v == "" {
- t.Fatal("NETBOX_SERVER must be set for acceptance tests.")
+ t.Fatal("NETBOX_SERVER_URL must be set for acceptance tests.")
}
if v := os.Getenv("NETBOX_API_TOKEN"); v == "" {
t.Fatal("NETBOX_API_TOKEN must be set for acceptance tests.")
@@ -83,7 +83,7 @@ func TestAccNetboxProviderConfigure_failure(t *testing.T) {
Steps: []resource.TestStep{
{
Config: testProviderConfig(acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)),
- ExpectError: regexp.MustCompile("Post \"https://fake.netbox.server/api/dcim/platforms/\": dial tcp: lookup fake.netbox.server: no such host"),
+ ExpectError: regexp.MustCompile("Post \"https://fake.netbox.server/api/dcim/platforms/\": dial tcp: lookup fake.netbox.server.*: no such host"),
},
},
})
diff --git a/netbox/resource_netbox_aggregate.go b/netbox/resource_netbox_aggregate.go
index fd89e365..f0b7ffd9 100644
--- a/netbox/resource_netbox_aggregate.go
+++ b/netbox/resource_netbox_aggregate.go
@@ -17,7 +17,7 @@ func resourceNetboxAggregate() *schema.Resource {
Update: resourceNetboxAggregateUpdate,
Delete: resourceNetboxAggregateDelete,
- Description: `:meta:subcategory:IP Address Management (IPAM):From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/ipam/#aggregates):
+ Description: `:meta:subcategory:IP Address Management (IPAM):From the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#aggregates):
> NetBox allows us to specify the portions of IP space that are interesting to us by defining aggregates. Typically, an aggregate will correspond to either an allocation of public (globally routable) IP space granted by a regional authority, or a private (internally-routable) designation.`,
diff --git a/netbox/resource_netbox_asn.go b/netbox/resource_netbox_asn.go
index ac4d92da..6cbd151b 100644
--- a/netbox/resource_netbox_asn.go
+++ b/netbox/resource_netbox_asn.go
@@ -16,7 +16,7 @@ func resourceNetboxAsn() *schema.Resource {
Update: resourceNetboxAsnUpdate,
Delete: resourceNetboxAsnDelete,
- Description: `:meta:subcategory:IP Address Management (IPAM):From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/ipam/#asn):
+ Description: `:meta:subcategory:IP Address Management (IPAM):From the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#asn):
> ASN is short for Autonomous System Number. This identifier is used in the BGP protocol to identify which "autonomous system" a particular prefix is originating and transiting through.
>
> The AS number model within NetBox allows you to model some of this real-world relationship.`,
diff --git a/netbox/resource_netbox_circuit.go b/netbox/resource_netbox_circuit.go
index aecd1839..f8f2c12f 100644
--- a/netbox/resource_netbox_circuit.go
+++ b/netbox/resource_netbox_circuit.go
@@ -17,7 +17,7 @@ func resourceNetboxCircuit() *schema.Resource {
Update: resourceNetboxCircuitUpdate,
Delete: resourceNetboxCircuitDelete,
- Description: `:meta:subcategory:Circuits:From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/circuits/#circuits_1):
+ Description: `:meta:subcategory:Circuits:From the [official documentation](https://docs.netbox.dev/en/stable/features/circuits/#circuits_1):
> A communications circuit represents a single physical link connecting exactly two endpoints, commonly referred to as its A and Z terminations. A circuit in NetBox may have zero, one, or two terminations defined. It is common to have only one termination defined when you don't necessarily care about the details of the provider side of the circuit, e.g. for Internet access circuits. Both terminations would likely be modeled for circuits which connect one customer site to another.
>
diff --git a/netbox/resource_netbox_circuit_provider.go b/netbox/resource_netbox_circuit_provider.go
index 738662b8..733485ed 100644
--- a/netbox/resource_netbox_circuit_provider.go
+++ b/netbox/resource_netbox_circuit_provider.go
@@ -17,7 +17,7 @@ func resourceNetboxCircuitProvider() *schema.Resource {
Update: resourceNetboxCircuitProviderUpdate,
Delete: resourceNetboxCircuitProviderDelete,
- Description: `:meta:subcategory:Circuits:From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/circuits/#providers):
+ Description: `:meta:subcategory:Circuits:From the [official documentation](https://docs.netbox.dev/en/stable/features/circuits/#providers):
> A circuit provider is any entity which provides some form of connectivity of among sites or organizations within a site. While this obviously includes carriers which offer Internet and private transit service, it might also include Internet exchange (IX) points and even organizations with whom you peer directly. Each circuit within NetBox must be assigned a provider and a circuit ID which is unique to that provider.
>
diff --git a/netbox/resource_netbox_circuit_termination.go b/netbox/resource_netbox_circuit_termination.go
index 7e5ee1cb..f52a09e4 100644
--- a/netbox/resource_netbox_circuit_termination.go
+++ b/netbox/resource_netbox_circuit_termination.go
@@ -17,7 +17,7 @@ func resourceNetboxCircuitTermination() *schema.Resource {
Update: resourceNetboxCircuitTerminationUpdate,
Delete: resourceNetboxCircuitTerminationDelete,
- Description: `:meta:subcategory:Circuits:From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/circuits/#circuit-terminations):
+ Description: `:meta:subcategory:Circuits:From the [official documentation](https://docs.netbox.dev/en/stable/features/circuits/#circuit-terminations):
> The association of a circuit with a particular site and/or device is modeled separately as a circuit termination. A circuit may have up to two terminations, labeled A and Z. A single-termination circuit can be used when you don't know (or care) about the far end of a circuit (for example, an Internet access circuit which connects to a transit provider). A dual-termination circuit is useful for tracking circuits which connect two sites.
>
diff --git a/netbox/resource_netbox_circuit_type.go b/netbox/resource_netbox_circuit_type.go
index 58d9329a..a1a9401d 100644
--- a/netbox/resource_netbox_circuit_type.go
+++ b/netbox/resource_netbox_circuit_type.go
@@ -17,7 +17,7 @@ func resourceNetboxCircuitType() *schema.Resource {
Update: resourceNetboxCircuitTypeUpdate,
Delete: resourceNetboxCircuitTypeDelete,
- Description: `:meta:subcategory:Circuits:From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/circuits/#circuit-types):
+ Description: `:meta:subcategory:Circuits:From the [official documentation](https://docs.netbox.dev/en/stable/features/circuits/#circuit-types):
> Circuits are classified by functional type. These types are completely customizable, and are typically used to convey the type of service being delivered over a circuit.`,
diff --git a/netbox/resource_netbox_cluster.go b/netbox/resource_netbox_cluster.go
index 03ba5c77..17fb2b92 100644
--- a/netbox/resource_netbox_cluster.go
+++ b/netbox/resource_netbox_cluster.go
@@ -16,7 +16,7 @@ func resourceNetboxCluster() *schema.Resource {
Update: resourceNetboxClusterUpdate,
Delete: resourceNetboxClusterDelete,
- Description: `:meta:subcategory:Virtualization:From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/virtualization/#clusters):
+ Description: `:meta:subcategory:Virtualization:From the [official documentation](https://docs.netbox.dev/en/stable/features/virtualization/#clusters):
> A cluster is a logical grouping of physical resources within which virtual machines run. A cluster must be assigned a type (technological classification), and may optionally be assigned to a cluster group, site, and/or tenant. Each cluster must have a unique name within its assigned group and/or site, if any.
>
@@ -39,6 +39,10 @@ func resourceNetboxCluster() *schema.Resource {
Type: schema.TypeInt,
Optional: true,
},
+ "tenant_id": &schema.Schema{
+ Type: schema.TypeInt,
+ Optional: true,
+ },
tagsKey: tagsSchema,
},
Importer: &schema.ResourceImporter{
@@ -68,6 +72,11 @@ func resourceNetboxClusterCreate(d *schema.ResourceData, m interface{}) error {
data.Site = &siteID
}
+ if tenantIDValue, ok := d.GetOk("tenant_id"); ok {
+ tenantID := int64(tenantIDValue.(int))
+ data.Tenant = &tenantID
+ }
+
tags, _ := getNestedTagListFromResourceDataSet(api, d.Get(tagsKey))
data.Tags = tags
@@ -115,6 +124,12 @@ func resourceNetboxClusterRead(d *schema.ResourceData, m interface{}) error {
d.Set("site_id", nil)
}
+ if res.GetPayload().Tenant != nil {
+ d.Set("tenant_id", res.GetPayload().Tenant.ID)
+ } else {
+ d.Set("tenant_id", nil)
+ }
+
d.Set(tagsKey, getTagListFromNestedTagList(res.GetPayload().Tags))
return nil
}
@@ -141,6 +156,11 @@ func resourceNetboxClusterUpdate(d *schema.ResourceData, m interface{}) error {
data.Site = &siteID
}
+ if tenantIDValue, ok := d.GetOk("tenant_id"); ok {
+ tenantID := int64(tenantIDValue.(int))
+ data.Tenant = &tenantID
+ }
+
tags, _ := getNestedTagListFromResourceDataSet(api, d.Get(tagsKey))
data.Tags = tags
diff --git a/netbox/resource_netbox_cluster_group.go b/netbox/resource_netbox_cluster_group.go
index d26ce5de..8a9aa165 100644
--- a/netbox/resource_netbox_cluster_group.go
+++ b/netbox/resource_netbox_cluster_group.go
@@ -17,7 +17,7 @@ func resourceNetboxClusterGroup() *schema.Resource {
Update: resourceNetboxClusterGroupUpdate,
Delete: resourceNetboxClusterGroupDelete,
- Description: `:meta:subcategory:Virtualization:From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/virtualization/#cluster-groups):
+ Description: `:meta:subcategory:Virtualization:From the [official documentation](https://docs.netbox.dev/en/stable/features/virtualization/#cluster-groups):
> Cluster groups may be created for the purpose of organizing clusters. The arrangement of clusters into groups is optional.`,
diff --git a/netbox/resource_netbox_cluster_test.go b/netbox/resource_netbox_cluster_test.go
index 2fc20ff2..294df900 100644
--- a/netbox/resource_netbox_cluster_test.go
+++ b/netbox/resource_netbox_cluster_test.go
@@ -64,7 +64,6 @@ resource "netbox_tag" "test_updatetag" {
name = "%[1]s-a"
}
-
resource "netbox_cluster_type" "test" {
name = "%[1]s"
}
@@ -73,6 +72,10 @@ resource "netbox_cluster_group" "test" {
name = "%[1]s"
}
+resource "netbox_tenant" "test" {
+ name = "%[1]s"
+}
+
resource "netbox_site" "test" {
name = "%[1]s"
status = "active"
@@ -82,12 +85,14 @@ resource "netbox_cluster" "test" {
name = "%[1]s"
cluster_type_id = netbox_cluster_type.test.id
cluster_group_id = netbox_cluster_group.test.id
+ tenant_id = netbox_tenant.test.id
tags = [netbox_tag.test.name, netbox_tag.test_updatetag.name]
}`, testName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("netbox_cluster.test", "name", testName),
resource.TestCheckResourceAttrPair("netbox_cluster.test", "cluster_type_id", "netbox_cluster_type.test", "id"),
resource.TestCheckResourceAttrPair("netbox_cluster.test", "cluster_group_id", "netbox_cluster_group.test", "id"),
+ resource.TestCheckResourceAttrPair("netbox_cluster.test", "tenant_id", "netbox_tenant.test", "id"),
resource.TestCheckResourceAttr("netbox_cluster.test", "tags.#", "2"),
resource.TestCheckResourceAttr("netbox_cluster.test", "tags.0", testName),
resource.TestCheckResourceAttr("netbox_cluster.test", "tags.1", fmt.Sprintf("%[1]s-a", testName)),
diff --git a/netbox/resource_netbox_cluster_type.go b/netbox/resource_netbox_cluster_type.go
index 1538a33e..143d0aa4 100644
--- a/netbox/resource_netbox_cluster_type.go
+++ b/netbox/resource_netbox_cluster_type.go
@@ -16,7 +16,7 @@ func resourceNetboxClusterType() *schema.Resource {
Update: resourceNetboxClusterTypeUpdate,
Delete: resourceNetboxClusterTypeDelete,
- Description: `:meta:subcategory:Virtualization:From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/virtualization/#cluster-types):
+ Description: `:meta:subcategory:Virtualization:From the [official documentation](https://docs.netbox.dev/en/stable/features/virtualization/#cluster-types):
> A cluster type represents a technology or mechanism by which a cluster is formed. For example, you might create a cluster type named "VMware vSphere" for a locally hosted cluster or "DigitalOcean NYC3" for one hosted by a cloud provider.`,
diff --git a/netbox/resource_netbox_contact.go b/netbox/resource_netbox_contact.go
new file mode 100644
index 00000000..423d8a71
--- /dev/null
+++ b/netbox/resource_netbox_contact.go
@@ -0,0 +1,152 @@
+package netbox
+
+import (
+ "strconv"
+
+ "github.com/fbreckle/go-netbox/netbox/client"
+ "github.com/fbreckle/go-netbox/netbox/client/tenancy"
+ "github.com/fbreckle/go-netbox/netbox/models"
+ "github.com/go-openapi/strfmt"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+)
+
+func resourceNetboxContact() *schema.Resource {
+ return &schema.Resource{
+ Create: resourceNetboxContactCreate,
+ Read: resourceNetboxContactRead,
+ Update: resourceNetboxContactUpdate,
+ Delete: resourceNetboxContactDelete,
+
+ Description: `:meta:subcategory:Tenancy:From the [official documentation](https://docs.netbox.dev/en/stable/features/contacts/#contacts_1):
+
+> A contact should represent an individual or permanent point of contact. Each contact must define a name, and may optionally include a title, phone number, email address, and related details.
+>
+> Contacts are reused for assignments, so each unique contact must be created only once and can be assigned to any number of NetBox objects, and there is no limit to the number of assigned contacts an object may have. Most core objects in NetBox can have contacts assigned to them.`,
+
+ Schema: map[string]*schema.Schema{
+ "name": &schema.Schema{
+ Type: schema.TypeString,
+ Required: true,
+ },
+ tagsKey: tagsSchema,
+ "group_id": &schema.Schema{
+ Type: schema.TypeInt,
+ Optional: true,
+ },
+ "email": &schema.Schema{
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "phone": &schema.Schema{
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ },
+ Importer: &schema.ResourceImporter{
+ State: schema.ImportStatePassthrough,
+ },
+ }
+}
+
+func resourceNetboxContactCreate(d *schema.ResourceData, m interface{}) error {
+ api := m.(*client.NetBoxAPI)
+
+ name := d.Get("name").(string)
+ phone := d.Get("phone").(string)
+ email := d.Get("email").(string)
+ group_id := int64(d.Get("group_id").(int))
+
+ tags, _ := getNestedTagListFromResourceDataSet(api, d.Get(tagsKey))
+
+ data := &models.WritableContact{}
+
+ data.Name = &name
+ data.Tags = tags
+ data.Phone = phone
+ data.Email = strfmt.Email(email)
+
+ if group_id != 0 {
+ data.Group = &group_id
+ }
+
+ params := tenancy.NewTenancyContactsCreateParams().WithData(data)
+
+ res, err := api.Tenancy.TenancyContactsCreate(params, nil)
+ if err != nil {
+ return err
+ }
+
+ d.SetId(strconv.FormatInt(res.GetPayload().ID, 10))
+
+ return resourceNetboxContactRead(d, m)
+}
+
+func resourceNetboxContactRead(d *schema.ResourceData, m interface{}) error {
+ api := m.(*client.NetBoxAPI)
+ id, _ := strconv.ParseInt(d.Id(), 10, 64)
+ params := tenancy.NewTenancyContactsReadParams().WithID(id)
+
+ res, err := api.Tenancy.TenancyContactsRead(params, nil)
+ if err != nil {
+ errorcode := err.(*tenancy.TenancyContactsReadDefault).Code()
+ if errorcode == 404 {
+ // If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html
+ d.SetId("")
+ return nil
+ }
+ return err
+ }
+
+ d.Set("name", res.GetPayload().Name)
+ d.Set("phone", res.GetPayload().Phone)
+ d.Set("email", res.GetPayload().Email)
+ if res.GetPayload().Group != nil {
+ d.Set("group_id", res.GetPayload().Group.ID)
+ }
+
+ return nil
+}
+
+func resourceNetboxContactUpdate(d *schema.ResourceData, m interface{}) error {
+ api := m.(*client.NetBoxAPI)
+
+ id, _ := strconv.ParseInt(d.Id(), 10, 64)
+ data := models.WritableContact{}
+
+ name := d.Get("name").(string)
+ phone := d.Get("phone").(string)
+ email := d.Get("email").(string)
+ group_id := int64(d.Get("group_id").(int))
+
+ tags, _ := getNestedTagListFromResourceDataSet(api, d.Get(tagsKey))
+
+ data.Name = &name
+ data.Tags = tags
+ data.Phone = phone
+ data.Email = strfmt.Email(email)
+ if group_id != 0 {
+ data.Group = &group_id
+ }
+
+ params := tenancy.NewTenancyContactsPartialUpdateParams().WithID(id).WithData(&data)
+
+ _, err := api.Tenancy.TenancyContactsPartialUpdate(params, nil)
+ if err != nil {
+ return err
+ }
+
+ return resourceNetboxContactRead(d, m)
+}
+
+func resourceNetboxContactDelete(d *schema.ResourceData, m interface{}) error {
+ api := m.(*client.NetBoxAPI)
+
+ id, _ := strconv.ParseInt(d.Id(), 10, 64)
+ params := tenancy.NewTenancyContactsDeleteParams().WithID(id)
+
+ _, err := api.Tenancy.TenancyContactsDelete(params, nil)
+ if err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/netbox/resource_netbox_contact_assignment.go b/netbox/resource_netbox_contact_assignment.go
new file mode 100644
index 00000000..487eb362
--- /dev/null
+++ b/netbox/resource_netbox_contact_assignment.go
@@ -0,0 +1,148 @@
+package netbox
+
+import (
+ "strconv"
+
+ "github.com/fbreckle/go-netbox/netbox/client"
+ "github.com/fbreckle/go-netbox/netbox/client/tenancy"
+ "github.com/fbreckle/go-netbox/netbox/models"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+)
+
+func resourceNetboxContactAssignment() *schema.Resource {
+ return &schema.Resource{
+ Create: resourceNetboxContactAssignmentCreate,
+ Read: resourceNetboxContactAssignmentRead,
+ Update: resourceNetboxContactAssignmentUpdate,
+ Delete: resourceNetboxContactAssignmentDelete,
+
+ Description: `:meta:subcategory:Tenancy:From the [official documentation](https://docs.netbox.dev/en/stable/features/contacts#contactassignments_1):
+
+> Much like tenancy, contact assignment enables you to track ownership of resources modeled in NetBox.`,
+
+ Schema: map[string]*schema.Schema{
+ "content_type": &schema.Schema{
+ Type: schema.TypeString,
+ Required: true,
+ },
+ "object_id": &schema.Schema{
+ Type: schema.TypeInt,
+ Required: true,
+ },
+ "contact_id": &schema.Schema{
+ Type: schema.TypeInt,
+ Required: true,
+ },
+ "role_id": &schema.Schema{
+ Type: schema.TypeInt,
+ Required: true,
+ },
+ },
+ Importer: &schema.ResourceImporter{
+ State: schema.ImportStatePassthrough,
+ },
+ }
+}
+
+func resourceNetboxContactAssignmentCreate(d *schema.ResourceData, m interface{}) error {
+ api := m.(*client.NetBoxAPI)
+
+ content_type := d.Get("content_type").(string)
+ object_id := int64(d.Get("object_id").(int))
+ contact_id := int64(d.Get("contact_id").(int))
+ role_id := int64(d.Get("role_id").(int))
+
+ data := &models.WritableContactAssignment{}
+
+ data.ContentType = &content_type
+ data.ObjectID = &object_id
+ data.Contact = &contact_id
+ data.Role = &role_id
+
+ params := tenancy.NewTenancyContactAssignmentsCreateParams().WithData(data)
+
+ res, err := api.Tenancy.TenancyContactAssignmentsCreate(params, nil)
+ if err != nil {
+ return err
+ }
+
+ d.SetId(strconv.FormatInt(res.GetPayload().ID, 10))
+
+ return resourceNetboxContactAssignmentRead(d, m)
+}
+
+func resourceNetboxContactAssignmentRead(d *schema.ResourceData, m interface{}) error {
+ api := m.(*client.NetBoxAPI)
+ id, _ := strconv.ParseInt(d.Id(), 10, 64)
+ params := tenancy.NewTenancyContactAssignmentsReadParams().WithID(id)
+
+ res, err := api.Tenancy.TenancyContactAssignmentsRead(params, nil)
+ if err != nil {
+ errorcode := err.(*tenancy.TenancyContactAssignmentsReadDefault).Code()
+ if errorcode == 404 {
+ // If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html
+ d.SetId("")
+ return nil
+ }
+ return err
+ }
+
+ d.Set("content_type", res.GetPayload().ContentType)
+
+ if res.GetPayload().ObjectID != nil {
+ d.Set("object_id", res.GetPayload().ObjectID)
+ }
+ if res.GetPayload().Contact != nil {
+ d.Set("contact_id", res.GetPayload().Contact.ID)
+ }
+ if res.GetPayload().Role != nil {
+ d.Set("role_id", res.GetPayload().Role.ID)
+ }
+
+ return nil
+}
+
+func resourceNetboxContactAssignmentUpdate(d *schema.ResourceData, m interface{}) error {
+ api := m.(*client.NetBoxAPI)
+
+ id, _ := strconv.ParseInt(d.Id(), 10, 64)
+ data := models.WritableContactAssignment{}
+
+ content_type := d.Get("content_type").(string)
+ object_id := int64(d.Get("object_id").(int))
+ contact_id := int64(d.Get("contact_id").(int))
+ role_id := int64(d.Get("role_id").(int))
+
+ data.ContentType = &content_type
+ if object_id != 0 {
+ data.ObjectID = &object_id
+ }
+ if contact_id != 0 {
+ data.Contact = &contact_id
+ }
+ if role_id != 0 {
+ data.Role = &role_id
+ }
+
+ params := tenancy.NewTenancyContactAssignmentsPartialUpdateParams().WithID(id).WithData(&data)
+
+ _, err := api.Tenancy.TenancyContactAssignmentsPartialUpdate(params, nil)
+ if err != nil {
+ return err
+ }
+
+ return resourceNetboxContactAssignmentRead(d, m)
+}
+
+func resourceNetboxContactAssignmentDelete(d *schema.ResourceData, m interface{}) error {
+ api := m.(*client.NetBoxAPI)
+
+ id, _ := strconv.ParseInt(d.Id(), 10, 64)
+ params := tenancy.NewTenancyContactAssignmentsDeleteParams().WithID(id)
+
+ _, err := api.Tenancy.TenancyContactAssignmentsDelete(params, nil)
+ if err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/netbox/resource_netbox_contact_assignment_test.go b/netbox/resource_netbox_contact_assignment_test.go
new file mode 100644
index 00000000..8206650f
--- /dev/null
+++ b/netbox/resource_netbox_contact_assignment_test.go
@@ -0,0 +1,99 @@
+package netbox
+
+import (
+ "fmt"
+ "log"
+ "testing"
+
+ "github.com/fbreckle/go-netbox/netbox/client"
+ "github.com/fbreckle/go-netbox/netbox/client/tenancy"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
+)
+
+func TestAccNetboxContactAssignment_basic(t *testing.T) {
+
+ testSlug := "contactassign"
+ testName := testAccGetTestName(testSlug)
+ randomSlug := testAccGetTestName(testSlug)
+ resource.ParallelTest(t, resource.TestCase{
+ Providers: testAccProviders,
+ PreCheck: func() { testAccPreCheck(t) },
+ Steps: []resource.TestStep{
+ {
+ Config: fmt.Sprintf(`
+resource "netbox_site" "test" {
+ name = "%[1]s"
+ slug = "%[2]s"
+}
+resource "netbox_device_role" "test" {
+ name = "%[1]s"
+ color_hex = "123456"
+}
+resource "netbox_device_type" "test" {
+ model = "%[1]s"
+ manufacturer_id = netbox_manufacturer.test.id
+}
+resource "netbox_device" "test" {
+ name = "%[1]s"
+ site_id = netbox_site.test.id
+ role_id = netbox_device_role.test.id
+ device_type_id = netbox_device_type.test.id
+}
+resource "netbox_contact" "test" {
+ name = "%[1]s"
+}
+resource "netbox_contact_role" "test" {
+ name = "%[1]s"
+}
+resource "netbox_manufacturer" "test" {
+ name = "%[1]s"
+}
+resource "netbox_contact_assignment" "test" {
+ content_type = "dcim.device"
+ object_id = netbox_device.test.id
+ contact_id = netbox_contact.test.id
+ role_id = netbox_contact_role.test.id
+}`, testName, randomSlug),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr("netbox_contact_assignment.test", "content_type", "dcim.device"),
+ resource.TestCheckResourceAttrPair("netbox_contact_assignment.test", "object_id", "netbox_device.test", "id"),
+ resource.TestCheckResourceAttrPair("netbox_contact_assignment.test", "contact_id", "netbox_contact.test", "id"),
+ resource.TestCheckResourceAttrPair("netbox_contact_assignment.test", "role_id", "netbox_contact_role.test", "id"),
+ ),
+ },
+ {
+ ResourceName: "netbox_contact_assignment.test",
+ ImportState: true,
+ ImportStateVerify: true,
+ },
+ },
+ })
+}
+
+func init() {
+ resource.AddTestSweepers("netbox_contact_assignment", &resource.Sweeper{
+ Name: "netbox_contact_assignment",
+ Dependencies: []string{},
+ F: func(region string) error {
+ m, err := sharedClientForRegion(region)
+ if err != nil {
+ return fmt.Errorf("Error getting client: %s", err)
+ }
+ api := m.(*client.NetBoxAPI)
+ params := tenancy.NewTenancyContactAssignmentsListParams()
+ res, err := api.Tenancy.TenancyContactAssignmentsList(params, nil)
+ if err != nil {
+ return err
+ }
+ for _, contactassignment := range res.GetPayload().Results {
+ deleteParams := tenancy.NewTenancyContactAssignmentsDeleteParams().WithID(contactassignment.ID)
+ _, err := api.Tenancy.TenancyContactAssignmentsDelete(deleteParams, nil)
+ if err != nil {
+ return err
+ }
+ log.Print("[DEBUG] Deleted a contact assignment")
+ }
+ return nil
+ },
+ })
+}
diff --git a/netbox/resource_netbox_contact_role.go b/netbox/resource_netbox_contact_role.go
new file mode 100644
index 00000000..fdfde213
--- /dev/null
+++ b/netbox/resource_netbox_contact_role.go
@@ -0,0 +1,135 @@
+package netbox
+
+import (
+ "strconv"
+
+ "github.com/fbreckle/go-netbox/netbox/client"
+ "github.com/fbreckle/go-netbox/netbox/client/tenancy"
+ "github.com/fbreckle/go-netbox/netbox/models"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
+)
+
+func resourceNetboxContactRole() *schema.Resource {
+ return &schema.Resource{
+ Create: resourceNetboxContactRoleCreate,
+ Read: resourceNetboxContactRoleRead,
+ Update: resourceNetboxContactRoleUpdate,
+ Delete: resourceNetboxContactRoleDelete,
+
+ Description: `:meta:subcategory:Tenancy:From the [official documentation](https://docs.netbox.dev/en/stable/features/contacts/#contactroles):
+
+> A contact role defines the relationship of a contact to an assigned object. For example, you might define roles for administrative, operational, and emergency contacts`,
+
+ Schema: map[string]*schema.Schema{
+ "name": &schema.Schema{
+ Type: schema.TypeString,
+ Required: true,
+ },
+ "slug": {
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ ValidateFunc: validation.StringLenBetween(0, 30),
+ },
+ },
+ Importer: &schema.ResourceImporter{
+ State: schema.ImportStatePassthrough,
+ },
+ }
+}
+
+func resourceNetboxContactRoleCreate(d *schema.ResourceData, m interface{}) error {
+ api := m.(*client.NetBoxAPI)
+
+ name := d.Get("name").(string)
+
+ data := &models.ContactRole{}
+
+ slugValue, slugOk := d.GetOk("slug")
+ // Default slug to name if not given
+ if !slugOk {
+ data.Slug = strToPtr(name)
+ } else {
+ data.Slug = strToPtr(slugValue.(string))
+ }
+
+ data.Name = &name
+ data.Tags = []*models.NestedTag{}
+
+ params := tenancy.NewTenancyContactRolesCreateParams().WithData(data)
+
+ res, err := api.Tenancy.TenancyContactRolesCreate(params, nil)
+ if err != nil {
+ return err
+ }
+
+ d.SetId(strconv.FormatInt(res.GetPayload().ID, 10))
+
+ return resourceNetboxContactRoleRead(d, m)
+}
+
+func resourceNetboxContactRoleRead(d *schema.ResourceData, m interface{}) error {
+ api := m.(*client.NetBoxAPI)
+ id, _ := strconv.ParseInt(d.Id(), 10, 64)
+ params := tenancy.NewTenancyContactRolesReadParams().WithID(id)
+
+ res, err := api.Tenancy.TenancyContactRolesRead(params, nil)
+
+ if err != nil {
+ errorcode := err.(*tenancy.TenancyContactRolesReadDefault).Code()
+ if errorcode == 404 {
+ // If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html
+ d.SetId("")
+ return nil
+ }
+ return err
+ }
+
+ contactrole := res.GetPayload()
+ d.Set("name", contactrole.Name)
+ d.Set("slug", contactrole.Slug)
+
+ return nil
+}
+
+func resourceNetboxContactRoleUpdate(d *schema.ResourceData, m interface{}) error {
+ api := m.(*client.NetBoxAPI)
+
+ id, _ := strconv.ParseInt(d.Id(), 10, 64)
+ data := models.ContactRole{}
+
+ name := d.Get("name").(string)
+ slugValue, slugOk := d.GetOk("slug")
+ // Default slug to name if not given
+ if !slugOk {
+ data.Slug = strToPtr(name)
+ } else {
+ data.Slug = strToPtr(slugValue.(string))
+ }
+
+ data.Name = &name
+ data.Tags = []*models.NestedTag{}
+
+ params := tenancy.NewTenancyContactRolesPartialUpdateParams().WithID(id).WithData(&data)
+
+ _, err := api.Tenancy.TenancyContactRolesPartialUpdate(params, nil)
+ if err != nil {
+ return err
+ }
+
+ return resourceNetboxContactRoleRead(d, m)
+}
+
+func resourceNetboxContactRoleDelete(d *schema.ResourceData, m interface{}) error {
+ api := m.(*client.NetBoxAPI)
+
+ id, _ := strconv.ParseInt(d.Id(), 10, 64)
+ params := tenancy.NewTenancyContactRolesDeleteParams().WithID(id)
+
+ _, err := api.Tenancy.TenancyContactRolesDelete(params, nil)
+ if err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/netbox/resource_netbox_contact_role_test.go b/netbox/resource_netbox_contact_role_test.go
new file mode 100644
index 00000000..851b665d
--- /dev/null
+++ b/netbox/resource_netbox_contact_role_test.go
@@ -0,0 +1,71 @@
+package netbox
+
+import (
+ "fmt"
+ "log"
+ "strings"
+ "testing"
+
+ "github.com/fbreckle/go-netbox/netbox/client"
+ "github.com/fbreckle/go-netbox/netbox/client/tenancy"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
+)
+
+func TestAccNetboxContactRole_basic(t *testing.T) {
+
+ testSlug := "contactrole"
+ testName := testAccGetTestName(testSlug)
+ randomSlug := testAccGetTestName(testSlug)
+
+ resource.ParallelTest(t, resource.TestCase{
+ Providers: testAccProviders,
+ PreCheck: func() { testAccPreCheck(t) },
+ Steps: []resource.TestStep{
+ {
+ Config: fmt.Sprintf(`
+resource "netbox_contact_role" "test" {
+ name = "%s"
+ slug = "%s"
+}`, testName, randomSlug),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr("netbox_contact_role.test", "name", testName),
+ ),
+ },
+ {
+ ResourceName: "netbox_contact_role.test",
+ ImportState: true,
+ ImportStateVerify: true,
+ },
+ },
+ })
+}
+
+func init() {
+ resource.AddTestSweepers("netbox_contact_role", &resource.Sweeper{
+ Name: "netbox_contact_role",
+ Dependencies: []string{},
+ F: func(region string) error {
+ m, err := sharedClientForRegion(region)
+ if err != nil {
+ return fmt.Errorf("Error getting client: %s", err)
+ }
+ api := m.(*client.NetBoxAPI)
+ params := tenancy.NewTenancyContactRolesListParams()
+ res, err := api.Tenancy.TenancyContactRolesList(params, nil)
+ if err != nil {
+ return err
+ }
+ for _, contactrole := range res.GetPayload().Results {
+ if strings.HasPrefix(*contactrole.Name, testPrefix) {
+ deleteParams := tenancy.NewTenancyContactRolesDeleteParams().WithID(contactrole.ID)
+ _, err := api.Tenancy.TenancyContactRolesDelete(deleteParams, nil)
+ if err != nil {
+ return err
+ }
+ log.Print("[DEBUG] Deleted a contact role")
+ }
+ }
+ return nil
+ },
+ })
+}
diff --git a/netbox/resource_netbox_contact_test.go b/netbox/resource_netbox_contact_test.go
new file mode 100644
index 00000000..cba6578e
--- /dev/null
+++ b/netbox/resource_netbox_contact_test.go
@@ -0,0 +1,138 @@
+package netbox
+
+import (
+ "fmt"
+ "log"
+ "strings"
+ "testing"
+
+ "github.com/fbreckle/go-netbox/netbox/client"
+ "github.com/fbreckle/go-netbox/netbox/client/tenancy"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
+)
+
+func testAccNetboxContactTagDependencies(testName string) string {
+ return fmt.Sprintf(`
+resource "netbox_tag" "test_a" {
+ name = "%[1]sa"
+}
+
+resource "netbox_tag" "test_b" {
+ name = "%[1]sb"
+}
+`, testName)
+}
+
+func TestAccNetboxContact_basic(t *testing.T) {
+
+ testSlug := "contact_basic"
+ testName := testAccGetTestName(testSlug)
+ resource.ParallelTest(t, resource.TestCase{
+ Providers: testAccProviders,
+ PreCheck: func() { testAccPreCheck(t) },
+ Steps: []resource.TestStep{
+ {
+ Config: fmt.Sprintf(`
+resource "netbox_contact" "test" {
+ name = "%s"
+}`, testName),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr("netbox_contact.test", "name", testName),
+ ),
+ },
+ {
+ Config: fmt.Sprintf(`
+resource "netbox_contact" "test" {
+ name = "%s"
+ email = "test@test.com"
+ phone = "123-123123"
+}`, testName),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr("netbox_contact.test", "name", testName),
+ resource.TestCheckResourceAttr("netbox_contact.test", "email", "test@test.com"),
+ resource.TestCheckResourceAttr("netbox_contact.test", "phone", "123-123123"),
+ ),
+ },
+ {
+ ResourceName: "netbox_contact.test",
+ ImportState: true,
+ ImportStateVerify: true,
+ },
+ },
+ })
+}
+
+func TestAccNetboxContact_tags(t *testing.T) {
+
+ testSlug := "contact_tags"
+ testName := testAccGetTestName(testSlug)
+ resource.ParallelTest(t, resource.TestCase{
+ Providers: testAccProviders,
+ PreCheck: func() { testAccPreCheck(t) },
+ Steps: []resource.TestStep{
+ {
+ Config: testAccNetboxContactTagDependencies(testName) + fmt.Sprintf(`
+resource "netbox_contact" "test_tags" {
+ name = "%[1]s"
+ tags = ["%[1]sa"]
+}`, testName),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr("netbox_contact.test_tags", "name", testName),
+ resource.TestCheckResourceAttr("netbox_contact.test_tags", "tags.#", "1"),
+ resource.TestCheckResourceAttr("netbox_contact.test_tags", "tags.0", testName+"a"),
+ ),
+ },
+ {
+ Config: testAccNetboxContactTagDependencies(testName) + fmt.Sprintf(`
+resource "netbox_contact" "test_tags" {
+ name = "%[1]s"
+ tags = ["%[1]sa", "%[1]sb"]
+}`, testName),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr("netbox_contact.test_tags", "tags.#", "2"),
+ resource.TestCheckResourceAttr("netbox_contact.test_tags", "tags.0", testName+"a"),
+ resource.TestCheckResourceAttr("netbox_contact.test_tags", "tags.1", testName+"b"),
+ ),
+ },
+ {
+ Config: testAccNetboxContactTagDependencies(testName) + fmt.Sprintf(`
+resource "netbox_contact" "test_tags" {
+ name = "%s"
+}`, testName),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr("netbox_contact.test_tags", "tags.#", "0"),
+ ),
+ },
+ },
+ })
+}
+
+func init() {
+ resource.AddTestSweepers("netbox_contact", &resource.Sweeper{
+ Name: "netbox_contact",
+ Dependencies: []string{},
+ F: func(region string) error {
+ m, err := sharedClientForRegion(region)
+ if err != nil {
+ return fmt.Errorf("Error getting client: %s", err)
+ }
+ api := m.(*client.NetBoxAPI)
+ params := tenancy.NewTenancyContactsListParams()
+ res, err := api.Tenancy.TenancyContactsList(params, nil)
+ if err != nil {
+ return err
+ }
+ for _, contact := range res.GetPayload().Results {
+ if strings.HasPrefix(*contact.Name, testPrefix) {
+ deleteParams := tenancy.NewTenancyContactsDeleteParams().WithID(contact.ID)
+ _, err := api.Tenancy.TenancyContactsDelete(deleteParams, nil)
+ if err != nil {
+ return err
+ }
+ log.Print("[DEBUG] Deleted a contact")
+ }
+ }
+ return nil
+ },
+ })
+}
diff --git a/netbox/resource_netbox_custom_field.go b/netbox/resource_netbox_custom_field.go
index 9c9e262c..fce528ee 100644
--- a/netbox/resource_netbox_custom_field.go
+++ b/netbox/resource_netbox_custom_field.go
@@ -73,6 +73,10 @@ func resourceCustomField() *schema.Resource {
Type: schema.TypeString,
Optional: true,
},
+ "group_name": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
"label": {
Type: schema.TypeString,
Optional: true,
@@ -109,6 +113,7 @@ func resourceNetboxCustomFieldUpdate(d *schema.ResourceData, m interface{}) erro
Name: strToPtr(d.Get("name").(string)),
Type: d.Get("type").(string),
Description: d.Get("description").(string),
+ GroupName: d.Get("group_name").(string),
Label: d.Get("label").(string),
Required: d.Get("required").(bool),
ValidationRegex: d.Get("validation_regex").(string),
@@ -159,6 +164,7 @@ func resourceNetboxCustomFieldCreate(d *schema.ResourceData, m interface{}) erro
Name: strToPtr(d.Get("name").(string)),
Type: d.Get("type").(string),
Description: d.Get("description").(string),
+ GroupName: d.Get("group_name").(string),
Label: d.Get("label").(string),
Required: d.Get("required").(bool),
ValidationRegex: d.Get("validation_regex").(string),
@@ -238,6 +244,7 @@ func resourceNetboxCustomFieldRead(d *schema.ResourceData, m interface{}) error
}
d.Set("description", res.GetPayload().Description)
+ d.Set("group_name", res.GetPayload().GroupName)
d.Set("label", res.GetPayload().Label)
d.Set("required", res.GetPayload().Required)
diff --git a/netbox/resource_netbox_custom_field_test.go b/netbox/resource_netbox_custom_field_test.go
index 2c1c95e1..0f487cf2 100644
--- a/netbox/resource_netbox_custom_field_test.go
+++ b/netbox/resource_netbox_custom_field_test.go
@@ -49,6 +49,7 @@ resource "netbox_custom_field" "test" {
name = "%s"
type = "integer"
content_types = ["virtualization.vminterface"]
+ group_name = "mygroup"
weight = 100
validation_maximum = 1000
validation_minimum = 10
@@ -57,6 +58,7 @@ resource "netbox_custom_field" "test" {
resource.TestCheckResourceAttr("netbox_custom_field.test", "name", testName),
resource.TestCheckResourceAttr("netbox_custom_field.test", "type", "integer"),
resource.TestCheckTypeSetElemAttr("netbox_custom_field.test", "content_types.*", "virtualization.vminterface"),
+ resource.TestCheckResourceAttr("netbox_custom_field.test", "group_name", "mygroup"),
resource.TestCheckResourceAttr("netbox_custom_field.test", "weight", "100"),
resource.TestCheckResourceAttr("netbox_custom_field.test", "validation_maximum", "1000"),
resource.TestCheckResourceAttr("netbox_custom_field.test", "validation_minimum", "10"),
diff --git a/netbox/resource_netbox_device.go b/netbox/resource_netbox_device.go
index aca383ea..0861260f 100644
--- a/netbox/resource_netbox_device.go
+++ b/netbox/resource_netbox_device.go
@@ -9,6 +9,7 @@ import (
"github.com/fbreckle/go-netbox/netbox/models"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)
func resourceNetboxDevice() *schema.Resource {
@@ -18,7 +19,7 @@ func resourceNetboxDevice() *schema.Resource {
UpdateContext: resourceNetboxDeviceUpdate,
DeleteContext: resourceNetboxDeviceDelete,
- Description: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/devices/#devices):
+ Description: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/features/devices/#devices):
> Every piece of hardware which is installed within a site or rack exists in NetBox as a device. Devices are measured in rack units (U) and can be half depth or full depth. A device may have a height of 0U: These devices do not consume vertical rack space and cannot be assigned to a particular rack unit. A common example of a 0U device is a vertically-mounted PDU.`,
@@ -39,6 +40,10 @@ func resourceNetboxDevice() *schema.Resource {
Type: schema.TypeInt,
Optional: true,
},
+ "platform_id": &schema.Schema{
+ Type: schema.TypeInt,
+ Optional: true,
+ },
"location_id": &schema.Schema{
Type: schema.TypeInt,
Optional: true,
@@ -65,6 +70,16 @@ func resourceNetboxDevice() *schema.Resource {
Computed: true,
},
customFieldsKey: customFieldsSchema,
+ "primary_ipv6": &schema.Schema{
+ Type: schema.TypeInt,
+ Computed: true,
+ },
+ "status": &schema.Schema{
+ Type: schema.TypeString,
+ Optional: true,
+ ValidateFunc: validation.StringInSlice([]string{"offline", "active", "planned", "staged", "failed", "inventory"}, false),
+ Default: "active",
+ },
},
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
@@ -93,12 +108,21 @@ func resourceNetboxDeviceCreate(ctx context.Context, d *schema.ResourceData, m i
serial := d.Get("serial").(string)
data.Serial = serial
+ status := d.Get("status").(string)
+ data.Status = status
+
tenantIDValue, ok := d.GetOk("tenant_id")
if ok {
tenantID := int64(tenantIDValue.(int))
data.Tenant = &tenantID
}
+ platformIDValue, ok := d.GetOk("platform_id")
+ if ok {
+ platformID := int64(platformIDValue.(int))
+ data.Platform = &platformID
+ }
+
locationIDValue, ok := d.GetOk("location_id")
if ok {
locationID := int64(locationIDValue.(int))
@@ -176,12 +200,24 @@ func resourceNetboxDeviceRead(ctx context.Context, d *schema.ResourceData, m int
d.Set("primary_ipv4", nil)
}
+ if device.PrimaryIp6 != nil {
+ d.Set("primary_ipv6", device.PrimaryIp6.ID)
+ } else {
+ d.Set("primary_ipv6", nil)
+ }
+
if device.Tenant != nil {
d.Set("tenant_id", device.Tenant.ID)
} else {
d.Set("tenant_id", nil)
}
+ if device.Platform != nil {
+ d.Set("platform_id", device.Platform.ID)
+ } else {
+ d.Set("platform_id", nil)
+ }
+
if device.Location != nil {
d.Set("location_id", device.Location.ID)
} else {
@@ -210,6 +246,8 @@ func resourceNetboxDeviceRead(ctx context.Context, d *schema.ResourceData, m int
d.Set("serial", device.Serial)
+ d.Set("status", device.Status.Value)
+
d.Set(tagsKey, getTagListFromNestedTagList(device.Tags))
cf := getCustomFields(device.CustomFields)
@@ -229,6 +267,9 @@ func resourceNetboxDeviceUpdate(ctx context.Context, d *schema.ResourceData, m i
name := d.Get("name").(string)
data.Name = &name
+ status := d.Get("status").(string)
+ data.Status = status
+
typeIDValue, ok := d.GetOk("device_type_id")
if ok {
typeID := int64(typeIDValue.(int))
@@ -241,6 +282,12 @@ func resourceNetboxDeviceUpdate(ctx context.Context, d *schema.ResourceData, m i
data.Tenant = &tenantID
}
+ platformIDValue, ok := d.GetOk("platform_id")
+ if ok {
+ platformID := int64(platformIDValue.(int))
+ data.Platform = &platformID
+ }
+
locationIDValue, ok := d.GetOk("location_id")
if ok {
locationID := int64(locationIDValue.(int))
@@ -274,10 +321,16 @@ func resourceNetboxDeviceUpdate(ctx context.Context, d *schema.ResourceData, m i
data.Comments = comments
}
- primaryIPValue, ok := d.GetOk("primary_ipv4")
+ primaryIP4Value, ok := d.GetOk("primary_ipv4")
+ if ok {
+ primaryIP4 := int64(primaryIP4Value.(int))
+ data.PrimaryIp4 = &primaryIP4
+ }
+
+ primaryIP6Value, ok := d.GetOk("primary_ipv6")
if ok {
- primaryIP := int64(primaryIPValue.(int))
- data.PrimaryIp4 = &primaryIP
+ primaryIP6 := int64(primaryIP6Value.(int))
+ data.PrimaryIp6 = &primaryIP6
}
data.Tags, _ = getNestedTagListFromResourceDataSet(api, d.Get(tagsKey))
diff --git a/netbox/resource_netbox_device_interface.go b/netbox/resource_netbox_device_interface.go
new file mode 100644
index 00000000..22f49e9e
--- /dev/null
+++ b/netbox/resource_netbox_device_interface.go
@@ -0,0 +1,256 @@
+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"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
+)
+
+func resourceNetboxDeviceInterface() *schema.Resource {
+ validModes := []string{"access", "tagged", "tagged-all"}
+
+ return &schema.Resource{
+ CreateContext: resourceNetboxDeviceInterfaceCreate,
+ ReadContext: resourceNetboxDeviceInterfaceRead,
+ UpdateContext: resourceNetboxDeviceInterfaceUpdate,
+ DeleteContext: resourceNetboxDeviceInterfaceDelete,
+
+ Description: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/features/device/#interface):
+
+> Interfaces in NetBox represent network interfaces used to exchange data with connected devices. On modern networks, these are most commonly Ethernet, but other types are supported as well. IP addresses and VLANs can be assigned to interfaces.`,
+ Schema: map[string]*schema.Schema{
+ "name": {
+ Type: schema.TypeString,
+ Required: true,
+ },
+ "device_id": {
+ Type: schema.TypeInt,
+ Required: true,
+ },
+ "description": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "enabled": {
+ Type: schema.TypeBool,
+ Optional: true,
+ Default: true,
+ },
+ "mac_address": {
+ Type: schema.TypeString,
+ Optional: true,
+ ValidateFunc: validation.IsMACAddress,
+ ForceNew: true,
+ },
+ "mgmtonly": {
+ Type: schema.TypeBool,
+ Optional: true,
+ },
+ "mode": {
+ Type: schema.TypeString,
+ Optional: true,
+ ValidateFunc: validation.StringInSlice(validModes, false),
+ },
+ "mtu": {
+ Type: schema.TypeInt,
+ Optional: true,
+ ValidateFunc: validation.IntBetween(1, 65536),
+ },
+ "type": {
+ Type: schema.TypeString,
+ Required: true,
+ },
+ tagsKey: tagsSchema,
+ "tagged_vlans": {
+ Type: schema.TypeSet,
+ Optional: true,
+ Elem: &schema.Schema{
+ Type: schema.TypeInt,
+ },
+ },
+ "untagged_vlan": {
+ Type: schema.TypeInt,
+ Optional: true,
+ },
+ },
+ Importer: &schema.ResourceImporter{
+ State: schema.ImportStatePassthrough,
+ },
+ }
+}
+
+func resourceNetboxDeviceInterfaceCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
+ api := m.(*client.NetBoxAPI)
+
+ var diags diag.Diagnostics
+
+ name := d.Get("name").(string)
+ description := d.Get("description").(string)
+ interface_type := d.Get("type").(string)
+ enabled := d.Get("enabled").(bool)
+ mgmtonly := d.Get("mgmtonly").(bool)
+ mode := d.Get("mode").(string)
+ tags, diagnostics := getNestedTagListFromResourceDataSet(api, d.Get(tagsKey))
+ if diagnostics != nil {
+ diags = append(diags, diagnostics...)
+ }
+ taggedVlans := toInt64List(d.Get("tagged_vlans"))
+ deviceID := int64(d.Get("device_id").(int))
+
+ data := models.WritableInterface{
+ Name: &name,
+ Description: description,
+ Type: &interface_type,
+ Enabled: enabled,
+ MgmtOnly: mgmtonly,
+ Mode: mode,
+ Tags: tags,
+ TaggedVlans: taggedVlans,
+ Device: &deviceID,
+ WirelessLans: []int64{},
+ }
+ if macAddress := d.Get("mac_address").(string); macAddress != "" {
+ data.MacAddress = &macAddress
+ }
+ if mtu, ok := d.Get("mtu").(int); ok && mtu != 0 {
+ data.Mtu = int64ToPtr(int64(mtu))
+ }
+ if untaggedVlan, ok := d.Get("untagged_vlan").(int); ok && untaggedVlan != 0 {
+ data.UntaggedVlan = int64ToPtr(int64(untaggedVlan))
+ }
+
+ params := dcim.NewDcimInterfacesCreateParams().WithData(&data)
+
+ res, err := api.Dcim.DcimInterfacesCreate(params, nil)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ d.SetId(strconv.FormatInt(res.GetPayload().ID, 10))
+
+ return diags
+}
+
+func resourceNetboxDeviceInterfaceRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
+ api := m.(*client.NetBoxAPI)
+ id, _ := strconv.ParseInt(d.Id(), 10, 64)
+
+ var diags diag.Diagnostics
+
+ params := dcim.NewDcimInterfacesReadParams().WithID(id)
+
+ res, err := api.Dcim.DcimInterfacesRead(params, nil)
+ if err != nil {
+ errorcode := err.(*dcim.DcimInterfacesReadDefault).Code()
+ if errorcode == 404 {
+ // If the ID is updated to blank, this tells Terraform the resource no longer exists (maybe it was destroyed out of band). Just like the destroy callback, the Read function should gracefully handle this case. https://www.terraform.io/docs/extend/writing-custom-providers.html
+ d.SetId("")
+ return nil
+ }
+ return diag.FromErr(err)
+ }
+
+ iface := res.GetPayload()
+
+ d.Set("name", iface.Name)
+ d.Set("description", iface.Description)
+ d.Set("type", iface.Type.Value)
+ d.Set("enabled", iface.Enabled)
+ d.Set("mgmtonly", iface.MgmtOnly)
+ d.Set("mac_address", iface.MacAddress)
+ d.Set("mtu", iface.Mtu)
+ d.Set(tagsKey, getTagListFromNestedTagList(iface.Tags))
+ d.Set("tagged_vlans", getIDsFromNestedVLANDevice(iface.TaggedVlans))
+ d.Set("device_id", iface.Device.ID)
+
+ if iface.Mode != nil {
+ d.Set("mode", iface.Mode.Value)
+ }
+ if iface.UntaggedVlan != nil {
+ d.Set("untagged_vlan", iface.UntaggedVlan.ID)
+ }
+
+ return diags
+}
+
+func resourceNetboxDeviceInterfaceUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
+ api := m.(*client.NetBoxAPI)
+
+ var diags diag.Diagnostics
+
+ id, _ := strconv.ParseInt(d.Id(), 10, 64)
+
+ name := d.Get("name").(string)
+ description := d.Get("description").(string)
+ interface_type := d.Get("type").(string)
+ enabled := d.Get("enabled").(bool)
+ mgmtonly := d.Get("mgmtonly").(bool)
+ mode := d.Get("mode").(string)
+ tags, diagnostics := getNestedTagListFromResourceDataSet(api, d.Get(tagsKey))
+ if diagnostics != nil {
+ diags = append(diags, diagnostics...)
+ }
+ taggedVlans := toInt64List(d.Get("tagged_vlans"))
+ deviceID := int64(d.Get("device_id").(int))
+
+ data := models.WritableInterface{
+ Name: &name,
+ Description: description,
+ Type: &interface_type,
+ Enabled: enabled,
+ MgmtOnly: mgmtonly,
+ Mode: mode,
+ Tags: tags,
+ TaggedVlans: taggedVlans,
+ Device: &deviceID,
+ WirelessLans: []int64{},
+ }
+
+ if d.HasChange("mac_address") {
+ macAddress := d.Get("mac_address").(string)
+ data.MacAddress = &macAddress
+ }
+ if d.HasChange("mtu") {
+ mtu := int64(d.Get("mtu").(int))
+ data.Mtu = &mtu
+ }
+ if d.HasChange("untagged_vlan") {
+ untaggedvlan := int64(d.Get("untagged_vlan").(int))
+ data.UntaggedVlan = &untaggedvlan
+ }
+
+ params := dcim.NewDcimInterfacesPartialUpdateParams().WithID(id).WithData(&data)
+ _, err := api.Dcim.DcimInterfacesPartialUpdate(params, nil)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ return diags
+}
+
+func resourceNetboxDeviceInterfaceDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
+ api := m.(*client.NetBoxAPI)
+
+ id, _ := strconv.ParseInt(d.Id(), 10, 64)
+ params := dcim.NewDcimInterfacesDeleteParams().WithID(id)
+
+ _, err := api.Dcim.DcimInterfacesDelete(params, nil)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ return nil
+}
+
+func getIDsFromNestedVLANDevice(nestedvlans []*models.NestedVLAN) []int64 {
+ var vlans []int64
+ for _, vlan := range nestedvlans {
+ vlans = append(vlans, vlan.ID)
+ }
+ return vlans
+}
diff --git a/netbox/resource_netbox_device_interface_test.go b/netbox/resource_netbox_device_interface_test.go
new file mode 100644
index 00000000..723f57b5
--- /dev/null
+++ b/netbox/resource_netbox_device_interface_test.go
@@ -0,0 +1,273 @@
+package netbox
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "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"
+ log "github.com/sirupsen/logrus"
+)
+
+func testAccNetboxDeviceInterfaceFullDependencies(testName string) string {
+ return fmt.Sprintf(`
+
+resource "netbox_tag" "test" {
+ name = "%[1]s"
+}
+
+resource "netbox_site" "test" {
+ name = "%[1]s"
+ status = "active"
+}
+
+resource "netbox_device_role" "test" {
+ name = "%[1]s"
+ color_hex = "123456"
+}
+
+resource "netbox_manufacturer" "test" {
+ name = "%[1]s"
+}
+
+resource "netbox_device_type" "test" {
+ model = "%[1]s"
+ manufacturer_id = netbox_manufacturer.test.id
+}
+
+resource "netbox_device" "test" {
+ name = "%[1]s"
+ device_type_id = netbox_device_type.test.id
+ role_id = netbox_device_role.test.id
+ site_id = netbox_site.test.id
+}
+
+resource "netbox_vlan" "test1" {
+ name = "%[1]s_vlan1"
+ vid = 1001
+ tags = []
+}
+
+resource "netbox_vlan" "test2" {
+ name = "%[1]s_vlan2"
+ vid = 1002
+ tags = []
+}`, testName)
+}
+
+func testAccNetboxDeviceInterface_basic(testName string) string {
+ return fmt.Sprintf(`
+resource "netbox_device_interface" "test" {
+ name = "%s"
+ device_id = netbox_device.test.id
+ tags = ["%[1]s"]
+ type = "1000base-t"
+}`, testName)
+}
+
+func testAccNetboxDeviceInterface_opts(testName string, testMac string) string {
+ return fmt.Sprintf(`
+resource "netbox_device_interface" "test" {
+ name = "%[1]s"
+ description = "%[1]s"
+ enabled = true
+ mgmtonly = true
+ mac_address = "%[2]s"
+ mtu = 1440
+ device_id = netbox_device.test.id
+ type = "1000base-t"
+}`, testName, testMac)
+}
+
+func testAccNetboxDeviceInterface_vlans(testName string) string {
+ return fmt.Sprintf(`
+resource "netbox_device_interface" "test1" {
+ name = "%[1]s_1"
+ mode = "access"
+ untagged_vlan = netbox_vlan.test1.id
+ device_id = netbox_device.test.id
+ type = "1000base-t"
+}
+
+resource "netbox_device_interface" "test2" {
+ name = "%[1]s_2"
+ mode = "tagged"
+ tagged_vlans = [netbox_vlan.test2.id]
+ untagged_vlan = netbox_vlan.test1.id
+ device_id = netbox_device.test.id
+ type = "1000base-t"
+}
+
+resource "netbox_device_interface" "test3" {
+ name = "%[1]s_3"
+ mode = "tagged-all"
+ tagged_vlans = [netbox_vlan.test1.id, netbox_vlan.test2.id]
+ device_id = netbox_device.test.id
+ type = "1000base-t"
+}`, testName)
+}
+
+func TestAccNetboxDeviceInterface_basic(t *testing.T) {
+ testSlug := "iface_basic"
+ testName := testAccGetTestName(testSlug)
+ setUp := testAccNetboxDeviceInterfaceFullDependencies(testName)
+ resource.ParallelTest(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ Providers: testAccProviders,
+ CheckDestroy: testAccCheckDeviceInterfaceDestroy,
+ Steps: []resource.TestStep{
+ {
+ Config: setUp + testAccNetboxDeviceInterface_basic(testName),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr("netbox_device_interface.test", "name", testName),
+ resource.TestCheckResourceAttr("netbox_device_interface.test", "type", "1000base-t"),
+ resource.TestCheckResourceAttrPair("netbox_device_interface.test", "device_id", "netbox_device.test", "id"),
+ resource.TestCheckResourceAttr("netbox_device_interface.test", "tags.#", "1"),
+ resource.TestCheckResourceAttr("netbox_device_interface.test", "tags.0", testName),
+ ),
+ },
+ {
+ ResourceName: "netbox_device_interface.test",
+ ImportState: true,
+ ImportStateVerify: true,
+ },
+ },
+ })
+}
+
+func TestAccNetboxDeviceInterface_opts(t *testing.T) {
+ testSlug := "iface_mac"
+ testMac := "00:01:02:03:04:05"
+ testName := testAccGetTestName(testSlug)
+ setUp := testAccNetboxDeviceInterfaceFullDependencies(testName)
+ resource.ParallelTest(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ Providers: testAccProviders,
+ CheckDestroy: testAccCheckDeviceInterfaceDestroy,
+ Steps: []resource.TestStep{
+ {
+ Config: setUp + testAccNetboxDeviceInterface_opts(testName, testMac),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr("netbox_device_interface.test", "name", testName),
+ resource.TestCheckResourceAttr("netbox_device_interface.test", "type", "1000base-t"),
+ resource.TestCheckResourceAttr("netbox_device_interface.test", "description", testName),
+ resource.TestCheckResourceAttr("netbox_device_interface.test", "enabled", "true"),
+ resource.TestCheckResourceAttr("netbox_device_interface.test", "mgmtonly", "true"),
+ resource.TestCheckResourceAttr("netbox_device_interface.test", "mac_address", "00:01:02:03:04:05"),
+ resource.TestCheckResourceAttr("netbox_device_interface.test", "mtu", "1440"),
+ resource.TestCheckResourceAttrPair("netbox_device_interface.test", "device_id", "netbox_device.test", "id"),
+ ),
+ },
+ {
+ ResourceName: "netbox_device_interface.test",
+ ImportState: true,
+ ImportStateVerify: true,
+ },
+ },
+ })
+}
+
+func TestAccNetboxDeviceInterface_vlans(t *testing.T) {
+ testSlug := "iface_vlan"
+ testName := testAccGetTestName(testSlug)
+ setUp := testAccNetboxDeviceInterfaceFullDependencies(testName)
+ resource.ParallelTest(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ Providers: testAccProviders,
+ CheckDestroy: testAccCheckDeviceInterfaceDestroy,
+ Steps: []resource.TestStep{
+ {
+ Config: setUp + testAccNetboxDeviceInterface_vlans(testName),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr("netbox_device_interface.test1", "mode", "access"),
+ resource.TestCheckResourceAttr("netbox_device_interface.test2", "mode", "tagged"),
+ resource.TestCheckResourceAttr("netbox_device_interface.test3", "mode", "tagged-all"),
+ resource.TestCheckResourceAttrPair("netbox_device_interface.test1", "untagged_vlan", "netbox_vlan.test1", "id"),
+ resource.TestCheckResourceAttrPair("netbox_device_interface.test2", "untagged_vlan", "netbox_vlan.test1", "id"),
+ resource.TestCheckResourceAttrPair("netbox_device_interface.test2", "tagged_vlans.0", "netbox_vlan.test2", "id"),
+ resource.TestCheckResourceAttr("netbox_device_interface.test3", "tagged_vlans.#", "2"),
+ ),
+ },
+ {
+ ResourceName: "netbox_device_interface.test1",
+ ImportState: true,
+ ImportStateVerify: true,
+ },
+ {
+ ResourceName: "netbox_device_interface.test2",
+ ImportState: true,
+ ImportStateVerify: true,
+ },
+ {
+ ResourceName: "netbox_device_interface.test3",
+ ImportState: true,
+ ImportStateVerify: true,
+ },
+ },
+ })
+}
+
+func testAccCheckDeviceInterfaceDestroy(s *terraform.State) error {
+ // retrieve the connection established in Provider configuration
+ conn := testAccProvider.Meta().(*client.NetBoxAPI)
+
+ // loop through the resources in state, verifying each interface
+ // is destroyed
+ for _, rs := range s.RootModule().Resources {
+ if rs.Type != "netbox_device_interface" {
+ continue
+ }
+
+ // Retrieve our interface by referencing it's state ID for API lookup
+ stateID, _ := strconv.ParseInt(rs.Primary.ID, 10, 64)
+ params := dcim.NewDcimInterfacesReadParams().WithID(stateID)
+ _, err := conn.Dcim.DcimInterfacesRead(params, nil)
+
+ if err == nil {
+ return fmt.Errorf("device interface (%s) still exists", rs.Primary.ID)
+ }
+
+ if err != nil {
+ errorcode := err.(*dcim.DcimInterfacesReadDefault).Code()
+ if errorcode == 404 {
+ return nil
+ }
+ return err
+ }
+ }
+ return nil
+}
+
+func init() {
+ resource.AddTestSweepers("netbox_device_interface", &resource.Sweeper{
+ Name: "netbox_device_interface",
+ Dependencies: []string{},
+ F: func(region string) error {
+ m, err := sharedClientForRegion(region)
+ if err != nil {
+ return fmt.Errorf("Error getting client: %s", err)
+ }
+ api := m.(*client.NetBoxAPI)
+ params := dcim.NewDcimInterfacesListParams()
+ res, err := api.Dcim.DcimInterfacesList(params, nil)
+ if err != nil {
+ return err
+ }
+ for _, intrface := range res.GetPayload().Results {
+ if strings.HasPrefix(*intrface.Name, testPrefix) {
+ deleteParams := dcim.NewDcimInterfacesDeleteParams().WithID(intrface.ID)
+ _, err := api.Dcim.DcimInterfacesDelete(deleteParams, nil)
+ if err != nil {
+ return err
+ }
+ log.Print("[DEBUG] Deleted a device interface")
+ }
+ }
+ return nil
+ },
+ })
+}
diff --git a/netbox/resource_netbox_device_role.go b/netbox/resource_netbox_device_role.go
index 08578f37..d546a1f7 100644
--- a/netbox/resource_netbox_device_role.go
+++ b/netbox/resource_netbox_device_role.go
@@ -16,7 +16,7 @@ func resourceNetboxDeviceRole() *schema.Resource {
Update: resourceNetboxDeviceRoleUpdate,
Delete: resourceNetboxDeviceRoleDelete,
- Description: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/devices/#device-roles):
+ Description: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/features/devices/#device-roles):
> Devices can be organized by functional roles, which are fully customizable by the user. For example, you might create roles for core switches, distribution switches, and access switches within your network.`,
@@ -39,6 +39,7 @@ func resourceNetboxDeviceRole() *schema.Resource {
Type: schema.TypeString,
Required: true,
},
+ tagsKey: tagsSchema,
},
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
@@ -63,13 +64,15 @@ func resourceNetboxDeviceRoleCreate(d *schema.ResourceData, m interface{}) error
color := d.Get("color_hex").(string)
vmRole := d.Get("vm_role").(bool)
+ tags, _ := getNestedTagListFromResourceDataSet(api, d.Get(tagsKey))
+
params := dcim.NewDcimDeviceRolesCreateParams().WithData(
&models.DeviceRole{
Name: &name,
Slug: &slug,
Color: color,
VMRole: vmRole,
- Tags: []*models.NestedTag{},
+ Tags: tags,
},
)
@@ -104,6 +107,7 @@ func resourceNetboxDeviceRoleRead(d *schema.ResourceData, m interface{}) error {
d.Set("slug", res.GetPayload().Slug)
d.Set("vm_role", res.GetPayload().VMRole)
d.Set("color_hex", res.GetPayload().Color)
+ d.Set(tagsKey, getTagListFromNestedTagList(res.GetPayload().Tags))
return nil
}
@@ -131,7 +135,9 @@ func resourceNetboxDeviceRoleUpdate(d *schema.ResourceData, m interface{}) error
data.Name = &name
data.VMRole = vmRole
data.Color = color
- data.Tags = []*models.NestedTag{}
+
+ tags, _ := getNestedTagListFromResourceDataSet(api, d.Get(tagsKey))
+ data.Tags = tags
params := dcim.NewDcimDeviceRolesPartialUpdateParams().WithID(id).WithData(&data)
diff --git a/netbox/resource_netbox_device_test.go b/netbox/resource_netbox_device_test.go
index e6058acd..7df4c9fd 100644
--- a/netbox/resource_netbox_device_test.go
+++ b/netbox/resource_netbox_device_test.go
@@ -19,6 +19,10 @@ resource "netbox_tenant" "test" {
name = "%[1]s"
}
+resource "netbox_platform" "test" {
+ name = "%[1]s"
+}
+
resource "netbox_site" "test" {
name = "%[1]s"
status = "active"
@@ -83,23 +87,27 @@ resource "netbox_device" "test" {
name = "%[1]s"
comments = "thisisacomment"
tenant_id = netbox_tenant.test.id
+ platform_id = netbox_platform.test.id
role_id = netbox_device_role.test.id
device_type_id = netbox_device_type.test.id
tags = ["%[1]sa"]
site_id = netbox_site.test.id
cluster_id = netbox_cluster.test.id
location_id = netbox_location.test.id
+ status = "staged"
serial = "ABCDEF"
custom_fields = {"${netbox_custom_field.test.name}" = "13"}
}`, testName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("netbox_device.test", "name", testName),
resource.TestCheckResourceAttrPair("netbox_device.test", "tenant_id", "netbox_tenant.test", "id"),
+ resource.TestCheckResourceAttrPair("netbox_device.test", "platform_id", "netbox_platform.test", "id"),
resource.TestCheckResourceAttrPair("netbox_device.test", "location_id", "netbox_location.test", "id"),
resource.TestCheckResourceAttrPair("netbox_device.test", "role_id", "netbox_device_role.test", "id"),
resource.TestCheckResourceAttrPair("netbox_device.test", "site_id", "netbox_site.test", "id"),
resource.TestCheckResourceAttrPair("netbox_device.test", "cluster_id", "netbox_cluster.test", "id"),
resource.TestCheckResourceAttr("netbox_device.test", "comments", "thisisacomment"),
+ resource.TestCheckResourceAttr("netbox_device.test", "status", "staged"),
resource.TestCheckResourceAttr("netbox_device.test", "serial", "ABCDEF"),
resource.TestCheckResourceAttr("netbox_device.test", "tags.#", "1"),
resource.TestCheckResourceAttr("netbox_device.test", "tags.0", testName+"a"),
diff --git a/netbox/resource_netbox_device_type.go b/netbox/resource_netbox_device_type.go
index 9bfee68c..7dddaa0e 100644
--- a/netbox/resource_netbox_device_type.go
+++ b/netbox/resource_netbox_device_type.go
@@ -17,7 +17,7 @@ func resourceNetboxDeviceType() *schema.Resource {
Update: resourceNetboxDeviceTypeUpdate,
Delete: resourceNetboxDeviceTypeDelete,
- Description: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/device-types/#device-types_1):
+ Description: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/features/device-types/#device-types_1):
> A device type represents a particular make and model of hardware that exists in the real world. Device types define the physical attributes of a device (rack height and depth) and its individual components (console, power, network interfaces, and so on).`,
diff --git a/netbox/resource_netbox_interface.go b/netbox/resource_netbox_interface.go
index e7fd9684..81b548dc 100644
--- a/netbox/resource_netbox_interface.go
+++ b/netbox/resource_netbox_interface.go
@@ -2,7 +2,6 @@ package netbox
import (
"context"
- "regexp"
"strconv"
"github.com/fbreckle/go-netbox/netbox/client"
@@ -22,7 +21,7 @@ func resourceNetboxInterface() *schema.Resource {
UpdateContext: resourceNetboxInterfaceUpdate,
DeleteContext: resourceNetboxInterfaceDelete,
- Description: `:meta:subcategory:Virtualization:From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/virtualization/#interfaces):
+ Description: `:meta:subcategory:Virtualization:From the [official documentation](https://docs.netbox.dev/en/stable/features/virtualization/#interfaces):
> Virtual machine interfaces behave similarly to device interfaces, and can be assigned to VRFs, and may have IP addresses, VLANs, and services attached to them. However, given their virtual nature, they lack properties pertaining to physical attributes. For example, VM interfaces do not have a physical type and cannot have cables attached to them.`,
Schema: map[string]*schema.Schema{
@@ -44,12 +43,10 @@ func resourceNetboxInterface() *schema.Resource {
Default: true,
},
"mac_address": {
- Type: schema.TypeString,
- Optional: true,
- ValidateFunc: validation.StringMatch(
- regexp.MustCompile("^([A-Z0-9]{2}:){5}[A-Z0-9]{2}$"),
- "Must be like AA:AA:AA:AA:AA"),
- ForceNew: true,
+ Type: schema.TypeString,
+ Optional: true,
+ ValidateFunc: validation.IsMACAddress,
+ ForceNew: true,
},
"mode": {
Type: schema.TypeString,
diff --git a/netbox/resource_netbox_ip_address.go b/netbox/resource_netbox_ip_address.go
index f8988c04..01711910 100644
--- a/netbox/resource_netbox_ip_address.go
+++ b/netbox/resource_netbox_ip_address.go
@@ -17,7 +17,7 @@ func resourceNetboxIPAddress() *schema.Resource {
Update: resourceNetboxIPAddressUpdate,
Delete: resourceNetboxIPAddressDelete,
- Description: `:meta:subcategory:IP Address Management (IPAM):From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/ipam/#ip-addresses):
+ Description: `:meta:subcategory:IP Address Management (IPAM):From the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#ip-addresses):
> An IP address comprises a single host address (either IPv4 or IPv6) and its subnet mask. Its mask should match exactly how the IP address is configured on an interface in the real world.
>
diff --git a/netbox/resource_netbox_ip_range.go b/netbox/resource_netbox_ip_range.go
index 6b1e5cc2..c88fb36a 100644
--- a/netbox/resource_netbox_ip_range.go
+++ b/netbox/resource_netbox_ip_range.go
@@ -17,7 +17,7 @@ func resourceNetboxIpRange() *schema.Resource {
Update: resourceNetboxIpRangeUpdate,
Delete: resourceNetboxIpRangeDelete,
- Description: `:meta:subcategory:IP Address Management (IPAM):From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/ipam/#ip-ranges):
+ Description: `:meta:subcategory:IP Address Management (IPAM):From the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#ip-ranges):
> This model represents an arbitrary range of individual IPv4 or IPv6 addresses, inclusive of its starting and ending addresses. For instance, the range 192.0.2.10 to 192.0.2.20 has eleven members. (The total member count is available as the size property on an IPRange instance.) Like prefixes and IP addresses, each IP range may optionally be assigned to a VRF and/or tenant.`,
diff --git a/netbox/resource_netbox_ipam_role.go b/netbox/resource_netbox_ipam_role.go
index 8b9a6426..9ebca357 100644
--- a/netbox/resource_netbox_ipam_role.go
+++ b/netbox/resource_netbox_ipam_role.go
@@ -17,7 +17,7 @@ func resourceNetboxIpamRole() *schema.Resource {
Update: resourceNetboxIpamRoleUpdate,
Delete: resourceNetboxIpamRoleDelete,
- Description: `:meta:subcategory:IP Address Management (IPAM):From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/ipam/#prefixvlan-roles):
+ Description: `:meta:subcategory:IP Address Management (IPAM):From the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#prefixvlan-roles):
> A role indicates the function of a prefix or VLAN. For example, you might define Data, Voice, and Security roles. Generally, a prefix will be assigned the same functional role as the VLAN to which it is assigned (if any).`,
diff --git a/netbox/resource_netbox_location.go b/netbox/resource_netbox_location.go
index 3ab395f8..2fdc3e4a 100644
--- a/netbox/resource_netbox_location.go
+++ b/netbox/resource_netbox_location.go
@@ -17,7 +17,7 @@ func resourceNetboxLocation() *schema.Resource {
Update: resourceNetboxLocationUpdate,
Delete: resourceNetboxLocationDelete,
- Description: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/sites-and-racks/#locations):
+ Description: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/features/sites-and-racks/#locations):
> Racks and devices can be grouped by location within a site. A location may represent a floor, room, cage, or similar organizational unit. Locations can be nested to form a hierarchy. For example, you may have floors within a site, and rooms within a floor.
diff --git a/netbox/resource_netbox_manufacturer.go b/netbox/resource_netbox_manufacturer.go
index 7ced8e3a..16d39cf9 100644
--- a/netbox/resource_netbox_manufacturer.go
+++ b/netbox/resource_netbox_manufacturer.go
@@ -17,7 +17,7 @@ func resourceNetboxManufacturer() *schema.Resource {
Update: resourceNetboxManufacturerUpdate,
Delete: resourceNetboxManufacturerDelete,
- Description: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/device-types/#manufacturers):
+ Description: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/features/device-types/#manufacturers):
> A manufacturer represents the "make" of a device; e.g. Cisco or Dell. Each device type must be assigned to a manufacturer. (Inventory items and platforms may also be associated with manufacturers.) Each manufacturer must have a unique name and may have a description assigned to it.`,
diff --git a/netbox/resource_netbox_platform.go b/netbox/resource_netbox_platform.go
index 021d9cff..47ba771d 100644
--- a/netbox/resource_netbox_platform.go
+++ b/netbox/resource_netbox_platform.go
@@ -17,7 +17,7 @@ func resourceNetboxPlatform() *schema.Resource {
Update: resourceNetboxPlatformUpdate,
Delete: resourceNetboxPlatformDelete,
- Description: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/devices/#platforms):
+ Description: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/features/devices/#platforms):
> A platform defines the type of software running on a device or virtual machine. This can be helpful to model when it is necessary to distinguish between different versions or feature sets. Note that two devices of the same type may be assigned different platforms: For example, one Juniper MX240 might run Junos 14 while another runs Junos 15.`,
diff --git a/netbox/resource_netbox_prefix.go b/netbox/resource_netbox_prefix.go
index d279c2eb..317f68f5 100644
--- a/netbox/resource_netbox_prefix.go
+++ b/netbox/resource_netbox_prefix.go
@@ -17,7 +17,7 @@ func resourceNetboxPrefix() *schema.Resource {
Update: resourceNetboxPrefixUpdate,
Delete: resourceNetboxPrefixDelete,
- Description: `:meta:subcategory:IP Address Management (IPAM):From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/ipam/#prefixes):
+ Description: `:meta:subcategory:IP Address Management (IPAM):From the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#prefixes):
> A prefix is an IPv4 or IPv6 network and mask expressed in CIDR notation (e.g. 192.0.2.0/24). A prefix entails only the "network portion" of an IP address: All bits in the address not covered by the mask must be zero. (In other words, a prefix cannot be a specific IP address.)
>
diff --git a/netbox/resource_netbox_prefix_test.go b/netbox/resource_netbox_prefix_test.go
index b4adae7a..c945fcd1 100644
--- a/netbox/resource_netbox_prefix_test.go
+++ b/netbox/resource_netbox_prefix_test.go
@@ -202,6 +202,19 @@ resource "netbox_prefix" "test" {
resource.TestCheckResourceAttr("netbox_prefix.test", "mark_utilized", "true"),
),
},
+ {
+ Config: testAccNetboxPrefixFullDependencies(testName, randomSlug, testVid) + fmt.Sprintf(`
+resource "netbox_prefix" "test" {
+ prefix = "%s"
+ description = "%s 2"
+ status = "active"
+}`, testPrefix, testDesc),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr("netbox_prefix.test", "prefix", testPrefix),
+ resource.TestCheckResourceAttr("netbox_prefix.test", "status", "active"),
+ resource.TestCheckResourceAttr("netbox_prefix.test", "description", fmt.Sprintf("%s 2", testDesc)),
+ ),
+ },
{
ResourceName: "netbox_prefix.test",
ImportState: true,
diff --git a/netbox/resource_netbox_region.go b/netbox/resource_netbox_region.go
index 69b4a83b..46bd1834 100644
--- a/netbox/resource_netbox_region.go
+++ b/netbox/resource_netbox_region.go
@@ -17,7 +17,7 @@ func resourceNetboxRegion() *schema.Resource {
Update: resourceNetboxRegionUpdate,
Delete: resourceNetboxRegionDelete,
- Description: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/sites-and-racks/#regions):
+ Description: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/features/sites-and-racks/#regions):
> Sites can be arranged geographically using regions. A region might represent a continent, country, city, campus, or other area depending on your use case. Regions can be nested recursively to construct a hierarchy. For example, you might define several country regions, and within each of those several state or city regions to which sites are assigned.
>
diff --git a/netbox/resource_netbox_rir.go b/netbox/resource_netbox_rir.go
index 4cac86e1..7953431f 100644
--- a/netbox/resource_netbox_rir.go
+++ b/netbox/resource_netbox_rir.go
@@ -17,7 +17,7 @@ func resourceNetboxRir() *schema.Resource {
Update: resourceNetboxRirUpdate,
Delete: resourceNetboxRirDelete,
- Description: `:meta:subcategory:IP Address Management (IPAM):From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/ipam/#regional-internet-registries-rirs):
+ Description: `:meta:subcategory:IP Address Management (IPAM):From the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#regional-internet-registries-rirs):
> Regional Internet registries are responsible for the allocation of globally-routable address space. The five RIRs are ARIN, RIPE, APNIC, LACNIC, and AFRINIC. However, some address space has been set aside for internal use, such as defined in RFCs 1918 and 6598. NetBox considers these RFCs as a sort of RIR as well; that is, an authority which "owns" certain address space. There also exist lower-tier registries which serve particular geographic areas.`,
diff --git a/netbox/resource_netbox_service.go b/netbox/resource_netbox_service.go
index 0e65319c..a77438c4 100644
--- a/netbox/resource_netbox_service.go
+++ b/netbox/resource_netbox_service.go
@@ -17,7 +17,7 @@ func resourceNetboxService() *schema.Resource {
Update: resourceNetboxServiceUpdate,
Delete: resourceNetboxServiceDelete,
- Description: `:meta:subcategory:IP Address Management (IPAM):From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/services/#services):
+ Description: `:meta:subcategory:IP Address Management (IPAM):From the [official documentation](https://docs.netbox.dev/en/stable/features/services/#services):
> A service represents a layer four TCP or UDP service available on a device or virtual machine. For example, you might want to document that an HTTP service is running on a device. Each service includes a name, protocol, and port number; for example, "SSH (TCP/22)" or "DNS (UDP/53)."
>
@@ -34,8 +34,9 @@ func resourceNetboxService() *schema.Resource {
Required: true,
},
"protocol": &schema.Schema{
- Type: schema.TypeString,
- Required: true,
+ Type: schema.TypeString,
+ Required: true,
+ ValidateDiagFunc: validation.ToDiagFunc(validation.StringInSlice([]string{"tcp", "udp", "sctp"}, false)),
},
"port": &schema.Schema{
Type: schema.TypeInt,
diff --git a/netbox/resource_netbox_site.go b/netbox/resource_netbox_site.go
index 33fce0ef..598d8ffc 100644
--- a/netbox/resource_netbox_site.go
+++ b/netbox/resource_netbox_site.go
@@ -17,7 +17,7 @@ func resourceNetboxSite() *schema.Resource {
Update: resourceNetboxSiteUpdate,
Delete: resourceNetboxSiteDelete,
- Description: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/sites-and-racks/#sites):
+ Description: `:meta:subcategory:Data Center Inventory Management (DCIM):From the [official documentation](https://docs.netbox.dev/en/stable/features/sites-and-racks/#sites):
> How you choose to employ sites when modeling your network may vary depending on the nature of your organization, but generally a site will equate to a building or campus. For example, a chain of banks might create a site to represent each of its branches, a site for its corporate headquarters, and two additional sites for its presence in two colocation facilities.
>
@@ -62,6 +62,10 @@ func resourceNetboxSite() *schema.Resource {
Type: schema.TypeInt,
Optional: true,
},
+ "group_id": {
+ Type: schema.TypeInt,
+ Optional: true,
+ },
"tenant_id": {
Type: schema.TypeInt,
Optional: true,
@@ -127,6 +131,11 @@ func resourceNetboxSiteCreate(d *schema.ResourceData, m interface{}) error {
data.Region = int64ToPtr(int64(regionIDValue.(int)))
}
+ groupIDValue, ok := d.GetOk("group_id")
+ if ok {
+ data.Group = int64ToPtr(int64(groupIDValue.(int)))
+ }
+
tenantIDValue, ok := d.GetOk("tenant_id")
if ok {
data.Tenant = int64ToPtr(int64(tenantIDValue.(int)))
@@ -195,6 +204,12 @@ func resourceNetboxSiteRead(d *schema.ResourceData, m interface{}) error {
d.Set("region_id", nil)
}
+ if res.GetPayload().Group != nil {
+ d.Set("group_id", res.GetPayload().Group.ID)
+ } else {
+ d.Set("group_id", nil)
+ }
+
if res.GetPayload().Tenant != nil {
d.Set("tenant_id", res.GetPayload().Tenant.ID)
} else {
@@ -252,6 +267,11 @@ func resourceNetboxSiteUpdate(d *schema.ResourceData, m interface{}) error {
data.Region = int64ToPtr(int64(regionIDValue.(int)))
}
+ groupIDValue, ok := d.GetOk("group_id")
+ if ok {
+ data.Group = int64ToPtr(int64(groupIDValue.(int)))
+ }
+
tenantIDValue, ok := d.GetOk("tenant_id")
if ok {
data.Tenant = int64ToPtr(int64(tenantIDValue.(int)))
diff --git a/netbox/resource_netbox_site_test.go b/netbox/resource_netbox_site_test.go
index 3ef67bc0..0333e468 100644
--- a/netbox/resource_netbox_site_test.go
+++ b/netbox/resource_netbox_site_test.go
@@ -22,6 +22,9 @@ func TestAccNetboxSite_basic(t *testing.T) {
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(`
+resource "netbox_site_group" "test" {
+ name = "%[1]s"
+}
resource "netbox_rir" "test" {
name = "%[1]s"
}
@@ -38,6 +41,7 @@ resource "netbox_site" "test" {
description = "%[1]s"
facility = "%[1]s"
asn_ids = [netbox_asn.test.id]
+ group_id = netbox_site_group.test.id
}`, testName, randomSlug),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("netbox_site.test", "name", testName),
@@ -47,6 +51,7 @@ resource "netbox_site" "test" {
resource.TestCheckResourceAttr("netbox_site.test", "facility", testName),
resource.TestCheckResourceAttr("netbox_site.test", "asn_ids.#", "1"),
resource.TestCheckResourceAttrPair("netbox_site.test", "asn_ids.0", "netbox_asn.test", "id"),
+ resource.TestCheckResourceAttrPair("netbox_site.test", "group_id", "netbox_site_group.test", "id"),
),
},
{
diff --git a/netbox/resource_netbox_tenant.go b/netbox/resource_netbox_tenant.go
index b235738a..bf70361c 100644
--- a/netbox/resource_netbox_tenant.go
+++ b/netbox/resource_netbox_tenant.go
@@ -17,7 +17,7 @@ func resourceNetboxTenant() *schema.Resource {
Update: resourceNetboxTenantUpdate,
Delete: resourceNetboxTenantDelete,
- Description: `:meta:subcategory:Tenancy:From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/tenancy/#tenants):
+ Description: `:meta:subcategory:Tenancy:From the [official documentation](https://docs.netbox.dev/en/stable/features/tenancy/#tenants):
> A tenant represents a discrete grouping of resources used for administrative purposes. Typically, tenants are used to represent individual customers or internal departments within an organization.
>
@@ -39,6 +39,10 @@ func resourceNetboxTenant() *schema.Resource {
Type: schema.TypeInt,
Optional: true,
},
+ "description": &schema.Schema{
+ Type: schema.TypeString,
+ Optional: true,
+ },
},
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
@@ -51,6 +55,8 @@ func resourceNetboxTenantCreate(d *schema.ResourceData, m interface{}) error {
name := d.Get("name").(string)
group_id := int64(d.Get("group_id").(int))
+ description := d.Get("description").(string)
+
slugValue, slugOk := d.GetOk("slug")
var slug string
// Default slug to name attribute if not given
@@ -66,6 +72,7 @@ func resourceNetboxTenantCreate(d *schema.ResourceData, m interface{}) error {
data.Name = &name
data.Slug = &slug
+ data.Description = description
data.Tags = tags
if group_id != 0 {
@@ -102,6 +109,7 @@ func resourceNetboxTenantRead(d *schema.ResourceData, m interface{}) error {
d.Set("name", res.GetPayload().Name)
d.Set("slug", res.GetPayload().Slug)
+ d.Set("description", res.GetPayload().Description)
if res.GetPayload().Group != nil {
d.Set("group_id", res.GetPayload().Group.ID)
}
@@ -116,6 +124,7 @@ func resourceNetboxTenantUpdate(d *schema.ResourceData, m interface{}) error {
data := models.WritableTenant{}
name := d.Get("name").(string)
+ description := d.Get("description").(string)
group_id := int64(d.Get("group_id").(int))
slugValue, slugOk := d.GetOk("slug")
var slug string
@@ -130,6 +139,7 @@ func resourceNetboxTenantUpdate(d *schema.ResourceData, m interface{}) error {
data.Slug = &slug
data.Name = &name
+ data.Description = description
data.Tags = tags
if group_id != 0 {
data.Group = &group_id
diff --git a/netbox/resource_netbox_tenant_group.go b/netbox/resource_netbox_tenant_group.go
index f8b6b1de..7063ef05 100644
--- a/netbox/resource_netbox_tenant_group.go
+++ b/netbox/resource_netbox_tenant_group.go
@@ -17,7 +17,7 @@ func resourceNetboxTenantGroup() *schema.Resource {
Update: resourceNetboxTenantGroupUpdate,
Delete: resourceNetboxTenantGroupDelete,
- Description: `:meta:subcategory:Tenancy:From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/tenancy/#tenant-groups):
+ Description: `:meta:subcategory:Tenancy:From the [official documentation](https://docs.netbox.dev/en/stable/features/tenancy/#tenant-groups):
> Tenants can be organized by custom groups. For instance, you might create one group called "Customers" and one called "Departments." The assignment of a tenant to a group is optional.
>
diff --git a/netbox/resource_netbox_tenant_test.go b/netbox/resource_netbox_tenant_test.go
index 4dfd3a20..26f34619 100644
--- a/netbox/resource_netbox_tenant_test.go
+++ b/netbox/resource_netbox_tenant_test.go
@@ -27,6 +27,7 @@ func TestAccNetboxTenant_basic(t *testing.T) {
testSlug := "tenant_basic"
testName := testAccGetTestName(testSlug)
+ testDescription := testAccGetTestName(testSlug)
randomSlug := testAccGetTestName(testSlug)
resource.ParallelTest(t, resource.TestCase{
Providers: testAccProviders,
@@ -37,10 +38,12 @@ func TestAccNetboxTenant_basic(t *testing.T) {
resource "netbox_tenant" "test" {
name = "%s"
slug = "%s"
-}`, testName, randomSlug),
+ description = "%s"
+}`, testName, randomSlug, testDescription),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("netbox_tenant.test", "name", testName),
resource.TestCheckResourceAttr("netbox_tenant.test", "slug", randomSlug),
+ resource.TestCheckResourceAttr("netbox_tenant.test", "description", testDescription),
),
},
{
diff --git a/netbox/resource_netbox_virtual_machine.go b/netbox/resource_netbox_virtual_machine.go
index e98f6dc4..b4948d2a 100644
--- a/netbox/resource_netbox_virtual_machine.go
+++ b/netbox/resource_netbox_virtual_machine.go
@@ -19,11 +19,9 @@ func resourceNetboxVirtualMachine() *schema.Resource {
UpdateContext: resourceNetboxVirtualMachineUpdate,
DeleteContext: resourceNetboxVirtualMachineDelete,
- Description: `:meta:subcategory:Virtualization:From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/virtualization/#virtual-machines):
+ Description: `:meta:subcategory:Virtualization:From the [official documentation](https://docs.netbox.dev/en/stable/features/virtualization/#virtual-machines):
-> A virtual machine represents a virtual compute instance hosted within a cluster. Each VM must be assigned to exactly one cluster.
->
-> Like devices, each VM can be assigned a platform and/or functional role`,
+> A virtual machine is a virtualized compute instance. These behave in NetBox very similarly to device objects, but without any physical attributes. For example, a VM may have interfaces assigned to it with IP addresses and VLANs, however its interfaces cannot be connected via cables (because they are virtual). Each VM may also define its compute, memory, and storage resources as well.`,
Schema: map[string]*schema.Schema{
"name": &schema.Schema{
@@ -34,7 +32,6 @@ func resourceNetboxVirtualMachine() *schema.Resource {
Type: schema.TypeInt,
Optional: true,
AtLeastOneOf: []string{"site_id", "cluster_id"},
- Description: "If this is set to a cluster that has a site, you have to set `site_id` as well.",
},
"tenant_id": &schema.Schema{
Type: schema.TypeInt,
@@ -85,6 +82,10 @@ func resourceNetboxVirtualMachine() *schema.Resource {
Type: schema.TypeInt,
Computed: true,
},
+ "primary_ipv6": &schema.Schema{
+ Type: schema.TypeInt,
+ Computed: true,
+ },
customFieldsKey: customFieldsSchema,
},
Importer: &schema.ResourceImporter{
@@ -224,6 +225,12 @@ func resourceNetboxVirtualMachineRead(ctx context.Context, d *schema.ResourceDat
d.Set("primary_ipv4", nil)
}
+ if vm.PrimaryIp6 != nil {
+ d.Set("primary_ipv6", vm.PrimaryIp6.ID)
+ } else {
+ d.Set("primary_ipv6", nil)
+ }
+
if vm.Tenant != nil {
d.Set("tenant_id", vm.Tenant.ID)
} else {
@@ -356,10 +363,16 @@ func resourceNetboxVirtualMachineUpdate(ctx context.Context, d *schema.ResourceD
data.Comments = comments
}
- primaryIPValue, ok := d.GetOk("primary_ipv4")
+ primaryIP4Value, ok := d.GetOk("primary_ipv4")
+ if ok {
+ primaryIP4 := int64(primaryIP4Value.(int))
+ data.PrimaryIp4 = &primaryIP4
+ }
+
+ primaryIP6Value, ok := d.GetOk("primary_ipv6")
if ok {
- primaryIP := int64(primaryIPValue.(int))
- data.PrimaryIp4 = &primaryIP
+ primaryIP6 := int64(primaryIP6Value.(int))
+ data.PrimaryIp6 = &primaryIP6
}
data.Tags, _ = getNestedTagListFromResourceDataSet(api, d.Get(tagsKey))
diff --git a/netbox/resource_netbox_virtual_machine_test.go b/netbox/resource_netbox_virtual_machine_test.go
index e18fd7cf..e73932fe 100644
--- a/netbox/resource_netbox_virtual_machine_test.go
+++ b/netbox/resource_netbox_virtual_machine_test.go
@@ -3,7 +3,6 @@ package netbox
import (
"fmt"
"log"
- "regexp"
"strconv"
"strings"
"testing"
@@ -125,29 +124,6 @@ resource "netbox_virtual_machine" "only_site" {
})
}
-func TestAccNetboxVirtualMachine_ClusterOnly(t *testing.T) {
-
- testSlug := "vm_clstr"
- testName := testAccGetTestName(testSlug)
- resource.ParallelTest(t, resource.TestCase{
- PreCheck: func() { testAccPreCheck(t) },
- Providers: testAccProviders,
- CheckDestroy: testAccCheckVirtualMachineDestroy,
- Steps: []resource.TestStep{
- {
- Config: testAccNetboxVirtualMachineSiteClusterDependencies(testName) + fmt.Sprintf(`
-resource "netbox_virtual_machine" "only_cluster" {
- name = "%s"
- cluster_id = netbox_cluster.test.id
-}
-`, testName),
-
- ExpectError: regexp.MustCompile(".*The selected cluster.*is not assigned to this site \\(None\\).*"),
- },
- },
- })
-}
-
func TestAccNetboxVirtualMachine_ClusterWithoutSite(t *testing.T) {
testSlug := "vm_clstrnosite"
diff --git a/netbox/resource_netbox_vlan.go b/netbox/resource_netbox_vlan.go
index 346fa6f7..22447f00 100644
--- a/netbox/resource_netbox_vlan.go
+++ b/netbox/resource_netbox_vlan.go
@@ -17,7 +17,7 @@ func resourceNetboxVlan() *schema.Resource {
Update: resourceNetboxVlanUpdate,
Delete: resourceNetboxVlanDelete,
- Description: `:meta:subcategory:IP Address Management (IPAM):From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/vlans/#vlans):
+ Description: `:meta:subcategory:IP Address Management (IPAM):From the [official documentation](https://docs.netbox.dev/en/stable/features/vlans/#vlans):
> A VLAN represents an isolated layer two domain, identified by a name and a numeric ID (1-4094) as defined in IEEE 802.1Q. VLANs are arranged into VLAN groups to define scope and to enforce uniqueness.`,
diff --git a/netbox/resource_netbox_vrf.go b/netbox/resource_netbox_vrf.go
index 969e838d..c43cdf7b 100644
--- a/netbox/resource_netbox_vrf.go
+++ b/netbox/resource_netbox_vrf.go
@@ -16,7 +16,7 @@ func resourceNetboxVrf() *schema.Resource {
Update: resourceNetboxVrfUpdate,
Delete: resourceNetboxVrfDelete,
- Description: `:meta:subcategory:IP Address Management (IPAM):From the [official documentation](https://docs.netbox.dev/en/stable/core-functionality/ipam/#virtual-routing-and-forwarding-vrf):
+ Description: `:meta:subcategory:IP Address Management (IPAM):From the [official documentation](https://docs.netbox.dev/en/stable/features/ipam/#virtual-routing-and-forwarding-vrf):
> A VRF object in NetBox represents a virtual routing and forwarding (VRF) domain. Each VRF is essentially a separate routing table. VRFs are commonly used to isolate customers or organizations from one another within a network, or to route overlapping address space (e.g. multiple instances of the 10.0.0.0/8 space). Each VRF may be assigned to a specific tenant to aid in organizing the available IP space by customer or internal user.`,
diff --git a/netbox/tags.go b/netbox/tags.go
index 79ccc154..f214255f 100644
--- a/netbox/tags.go
+++ b/netbox/tags.go
@@ -21,6 +21,15 @@ var tagsSchema = &schema.Schema{
Set: schema.HashString,
}
+var tagsSchemaRead = &schema.Schema{
+ Type: schema.TypeSet,
+ Elem: &schema.Schema{
+ Type: schema.TypeString,
+ },
+ Computed: true,
+ Set: schema.HashString,
+}
+
func getNestedTagListFromResourceDataSet(client *client.NetBoxAPI, d interface{}) ([]*models.NestedTag, diag.Diagnostics) {
var diags diag.Diagnostics
diff --git a/templates/index.md.tmpl b/templates/index.md.tmpl
index cfeb6dbf..5c2a301b 100644
--- a/templates/index.md.tmpl
+++ b/templates/index.md.tmpl
@@ -16,6 +16,7 @@ Netbox often makes breaking API changes even in non-major releases. Check the ta
Provider version | Netbox version
--- | ---
+v3.0.x | v3.3.0 and up
v2.0.x | v3.2.0 and up
v1.6.x and up| v3.1.9
v1.1.x and up | v3.1.3