From c770ce9d5a0a1918e52189bdd6a99ff68a60337e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Nie=C3=9F?= Date: Sun, 30 Oct 2022 13:32:01 +0100 Subject: [PATCH] feat: Add suppport for missing customfield types --- examples/main.tf | 418 ++++++++++++++++-- .../netbox_ipam_aggregate/resource.tf | 38 +- .../netbox_ipam_ip_addresses/resource.tf | 38 +- .../netbox_ipam_ip_range/resource.tf | 38 +- .../resources/netbox_ipam_prefix/resource.tf | 38 +- .../resources/netbox_ipam_service/resource.tf | 38 +- .../resources/netbox_ipam_vlan/resource.tf | 38 +- .../netbox_tenancy_contact/resource.tf | 38 +- .../netbox_tenancy_contact_group/resource.tf | 38 +- .../netbox_tenancy_contact_role/resource.tf | 38 +- .../netbox_tenancy_tenant/resource.tf | 38 +- .../resource.tf | 38 +- .../netbox_virtualization_vm/resource.tf | 38 +- netbox/resource_netbox_ipam_aggregate.go | 27 +- netbox/resource_netbox_ipam_ip_addresses.go | 27 +- netbox/resource_netbox_ipam_ip_range.go | 27 +- netbox/resource_netbox_ipam_prefix.go | 27 +- netbox/resource_netbox_ipam_service.go | 27 +- netbox/resource_netbox_ipam_vlan.go | 36 +- netbox/resource_netbox_tenancy_contact.go | 36 +- .../resource_netbox_tenancy_contact_group.go | 31 +- .../resource_netbox_tenancy_contact_role.go | 27 +- netbox/resource_netbox_tenancy_tenant.go | 27 +- ...esource_netbox_virtualization_interface.go | 27 +- netbox/resource_netbox_virtualization_vm.go | 27 +- netbox/util.go | 126 +++++- 26 files changed, 927 insertions(+), 419 deletions(-) diff --git a/examples/main.tf b/examples/main.tf index 24312c14c..017591fa7 100644 --- a/examples/main.tf +++ b/examples/main.tf @@ -40,7 +40,7 @@ resource "netbox_tenancy_tenant" "tenant_test" { custom_field { name = "cf_selection" - type = "selection" + type = "select" value = "1" } @@ -51,9 +51,39 @@ resource "netbox_tenancy_tenant" "tenant_test" { } custom_field { - name = "cf_multiple_selection" - type = "multiple" - value = "0,1" + name = "cf_multi_selection" + type = "multiselect" + value = jsonencode([ + "0", + "1" + ]) + } + + custom_field { + name = "cf_json" + type = "json" + value = jsonencode({ + stringvalue = "string" + boolvalue = false + dictionary = { + numbervalue = 5 + } + }) + } + + custom_field { + name = "cf_object" + type = "object" + value = 1 + } + + custom_field { + name = "cf_multi_object" + type = "multiobject" + value = jsonencode([ + 1, + 2 + ]) } } @@ -143,7 +173,7 @@ resource "netbox_ipam_vlan" "vlan_test" { custom_field { name = "cf_selection" - type = "selection" + type = "select" value = "1" } @@ -154,9 +184,39 @@ resource "netbox_ipam_vlan" "vlan_test" { } custom_field { - name = "cf_multiple_selection" - type = "multiple" - value = "0,1" + name = "cf_multi_selection" + type = "multiselect" + value = jsonencode([ + "0", + "1" + ]) + } + + custom_field { + name = "cf_json" + type = "json" + value = jsonencode({ + stringvalue = "string" + boolvalue = false + dictionary = { + numbervalue = 5 + } + }) + } + + custom_field { + name = "cf_object" + type = "object" + value = 1 + } + + custom_field { + name = "cf_multi_object" + type = "multiobject" + value = jsonencode([ + 1, + 2 + ]) } } @@ -202,7 +262,7 @@ resource "netbox_ipam_prefix" "prefix_test" { custom_field { name = "cf_selection" - type = "selection" + type = "select" value = "1" } @@ -213,9 +273,39 @@ resource "netbox_ipam_prefix" "prefix_test" { } custom_field { - name = "cf_multiple_selection" - type = "multiple" - value = "0,1" + name = "cf_multi_selection" + type = "multiselect" + value = jsonencode([ + "0", + "1" + ]) + } + + custom_field { + name = "cf_json" + type = "json" + value = jsonencode({ + stringvalue = "string" + boolvalue = false + dictionary = { + numbervalue = 5 + } + }) + } + + custom_field { + name = "cf_object" + type = "object" + value = 1 + } + + custom_field { + name = "cf_multi_object" + type = "multiobject" + value = jsonencode([ + 1, + 2 + ]) } } @@ -265,7 +355,7 @@ resource "netbox_ipam_ip_range" "range_test" { custom_field { name = "cf_selection" - type = "selection" + type = "select" value = "1" } @@ -276,9 +366,39 @@ resource "netbox_ipam_ip_range" "range_test" { } custom_field { - name = "cf_multiple_selection" - type = "multiple" - value = "0,1" + name = "cf_multi_selection" + type = "multiselect" + value = jsonencode([ + "0", + "1" + ]) + } + + custom_field { + name = "cf_json" + type = "json" + value = jsonencode({ + stringvalue = "string" + boolvalue = false + dictionary = { + numbervalue = 5 + } + }) + } + + custom_field { + name = "cf_object" + type = "object" + value = 1 + } + + custom_field { + name = "cf_multi_object" + type = "multiobject" + value = jsonencode([ + 1, + 2 + ]) } } @@ -326,7 +446,7 @@ resource "netbox_ipam_ip_addresses" "ip_test" { custom_field { name = "cf_selection" - type = "selection" + type = "select" value = "1" } @@ -337,9 +457,39 @@ resource "netbox_ipam_ip_addresses" "ip_test" { } custom_field { - name = "cf_multiple_selection" - type = "multiple" - value = "0,1" + name = "cf_multi_selection" + type = "multiselect" + value = jsonencode([ + "0", + "1" + ]) + } + + custom_field { + name = "cf_json" + type = "json" + value = jsonencode({ + stringvalue = "string" + boolvalue = false + dictionary = { + numbervalue = 5 + } + }) + } + + custom_field { + name = "cf_object" + type = "object" + value = 1 + } + + custom_field { + name = "cf_multi_object" + type = "multiobject" + value = jsonencode([ + 1, + 2 + ]) } } @@ -410,7 +560,7 @@ resource "netbox_virtualization_vm" "vm_test" { custom_field { name = "cf_selection" - type = "selection" + type = "select" value = "1" } @@ -421,9 +571,39 @@ resource "netbox_virtualization_vm" "vm_test" { } custom_field { - name = "cf_multiple_selection" - type = "multiple" - value = "0,1" + name = "cf_multi_selection" + type = "multiselect" + value = jsonencode([ + "0", + "1" + ]) + } + + custom_field { + name = "cf_json" + type = "json" + value = jsonencode({ + stringvalue = "string" + boolvalue = false + dictionary = { + numbervalue = 5 + } + }) + } + + custom_field { + name = "cf_object" + type = "object" + value = 1 + } + + custom_field { + name = "cf_multi_object" + type = "multiobject" + value = jsonencode([ + 1, + 2 + ]) } } @@ -466,7 +646,7 @@ resource "netbox_ipam_service" "service_test" { custom_field { name = "cf_selection" - type = "selection" + type = "select" value = "1" } @@ -477,9 +657,39 @@ resource "netbox_ipam_service" "service_test" { } custom_field { - name = "cf_multiple_selection" - type = "multiple" - value = "0,1" + name = "cf_multi_selection" + type = "multiselect" + value = jsonencode([ + "0", + "1" + ]) + } + + custom_field { + name = "cf_json" + type = "json" + value = jsonencode({ + stringvalue = "string" + boolvalue = false + dictionary = { + numbervalue = 5 + } + }) + } + + custom_field { + name = "cf_object" + type = "object" + value = 1 + } + + custom_field { + name = "cf_multi_object" + type = "multiobject" + value = jsonencode([ + 1, + 2 + ]) } } @@ -532,7 +742,7 @@ resource "netbox_ipam_aggregate" "aggregate_test" { custom_field { name = "cf_selection" - type = "selection" + type = "select" value = "1" } @@ -543,9 +753,39 @@ resource "netbox_ipam_aggregate" "aggregate_test" { } custom_field { - name = "cf_multiple_selection" - type = "multiple" - value = "0,1" + name = "cf_multi_selection" + type = "multiselect" + value = jsonencode([ + "0", + "1" + ]) + } + + custom_field { + name = "cf_json" + type = "json" + value = jsonencode({ + stringvalue = "string" + boolvalue = false + dictionary = { + numbervalue = 5 + } + }) + } + + custom_field { + name = "cf_object" + type = "object" + value = 1 + } + + custom_field { + name = "cf_multi_object" + type = "multiobject" + value = jsonencode([ + 1, + 2 + ]) } } @@ -594,7 +834,7 @@ resource "netbox_tenancy_contact" "contact" { custom_field { name = "cf_selection" - type = "selection" + type = "select" value = "1" } @@ -605,9 +845,39 @@ resource "netbox_tenancy_contact" "contact" { } custom_field { - name = "cf_multiple_selection" - type = "multiple" - value = "0,1" + name = "cf_multi_selection" + type = "multiselect" + value = jsonencode([ + "0", + "1" + ]) + } + + custom_field { + name = "cf_json" + type = "json" + value = jsonencode({ + stringvalue = "string" + boolvalue = false + dictionary = { + numbervalue = 5 + } + }) + } + + custom_field { + name = "cf_object" + type = "object" + value = 1 + } + + custom_field { + name = "cf_multi_object" + type = "multiobject" + value = jsonencode([ + 1, + 2 + ]) } } @@ -652,7 +922,7 @@ resource "netbox_tenancy_contact_group" "contact_group_01" { custom_field { name = "cf_selection" - type = "selection" + type = "select" value = "1" } @@ -663,9 +933,39 @@ resource "netbox_tenancy_contact_group" "contact_group_01" { } custom_field { - name = "cf_multiple_selection" - type = "multiple" - value = "0,1" + name = "cf_multi_selection" + type = "multiselect" + value = jsonencode([ + "0", + "1" + ]) + } + + custom_field { + name = "cf_json" + type = "json" + value = jsonencode({ + stringvalue = "string" + boolvalue = false + dictionary = { + numbervalue = 5 + } + }) + } + + custom_field { + name = "cf_object" + type = "object" + value = 1 + } + + custom_field { + name = "cf_multi_object" + type = "multiobject" + value = jsonencode([ + 1, + 2 + ]) } } @@ -717,7 +1017,7 @@ resource "netbox_tenancy_contact_role" "contact_role_01" { custom_field { name = "cf_selection" - type = "selection" + type = "select" value = "1" } @@ -728,9 +1028,39 @@ resource "netbox_tenancy_contact_role" "contact_role_01" { } custom_field { - name = "cf_multiple_selection" - type = "multiple" - value = "0,1" + name = "cf_multi_selection" + type = "multiselect" + value = jsonencode([ + "0", + "1" + ]) + } + + custom_field { + name = "cf_json" + type = "json" + value = jsonencode({ + stringvalue = "string" + boolvalue = false + dictionary = { + numbervalue = 5 + } + }) + } + + custom_field { + name = "cf_object" + type = "object" + value = 1 + } + + custom_field { + name = "cf_multi_object" + type = "multiobject" + value = jsonencode([ + 1, + 2 + ]) } } diff --git a/examples/resources/netbox_ipam_aggregate/resource.tf b/examples/resources/netbox_ipam_aggregate/resource.tf index 2363ddee1..ca20ecaed 100644 --- a/examples/resources/netbox_ipam_aggregate/resource.tf +++ b/examples/resources/netbox_ipam_aggregate/resource.tf @@ -34,7 +34,7 @@ resource "netbox_ipam_aggregate" "aggregate_test" { custom_field { name = "cf_selection" - type = "selection" + type = "select" value = "1" } @@ -45,8 +45,38 @@ resource "netbox_ipam_aggregate" "aggregate_test" { } custom_field { - name = "cf_multiple_selection" - type = "multiple" - value = "0,1" + name = "cf_multi_selection" + type = "multiselect" + value = jsonencode([ + "0", + "1" + ]) + } + + custom_field { + name = "cf_json" + type = "json" + value = jsonencode({ + stringvalue = "string" + boolvalue = false + dictionary = { + numbervalue = 5 + } + }) + } + + custom_field { + name = "cf_object" + type = "object" + value = 1 + } + + custom_field { + name = "cf_multi_object" + type = "multiobject" + value = jsonencode([ + 1, + 2 + ]) } } diff --git a/examples/resources/netbox_ipam_ip_addresses/resource.tf b/examples/resources/netbox_ipam_ip_addresses/resource.tf index e246338de..d3edcb914 100644 --- a/examples/resources/netbox_ipam_ip_addresses/resource.tf +++ b/examples/resources/netbox_ipam_ip_addresses/resource.tf @@ -34,7 +34,7 @@ resource "netbox_ipam_ip_addresses" "ip_test" { custom_field { name = "cf_selection" - type = "selection" + type = "select" value = "1" } @@ -45,9 +45,39 @@ resource "netbox_ipam_ip_addresses" "ip_test" { } custom_field { - name = "cf_multiple_selection" - type = "multiple" - value = "0,1" + name = "cf_multi_selection" + type = "multiselect" + value = jsonencode([ + "0", + "1" + ]) + } + + custom_field { + name = "cf_json" + type = "json" + value = jsonencode({ + stringvalue = "string" + boolvalue = false + dictionary = { + numbervalue = 5 + } + }) + } + + custom_field { + name = "cf_object" + type = "object" + value = 1 + } + + custom_field { + name = "cf_multi_object" + type = "multiobject" + value = jsonencode([ + 1, + 2 + ]) } } diff --git a/examples/resources/netbox_ipam_ip_range/resource.tf b/examples/resources/netbox_ipam_ip_range/resource.tf index fb479d520..9adfba47e 100644 --- a/examples/resources/netbox_ipam_ip_range/resource.tf +++ b/examples/resources/netbox_ipam_ip_range/resource.tf @@ -36,7 +36,7 @@ resource "netbox_ipam_ip_range" "range_test" { custom_field { name = "cf_selection" - type = "selection" + type = "select" value = "1" } @@ -47,8 +47,38 @@ resource "netbox_ipam_ip_range" "range_test" { } custom_field { - name = "cf_multiple_selection" - type = "multiple" - value = "0,1" + name = "cf_multi_selection" + type = "multiselect" + value = jsonencode([ + "0", + "1" + ]) + } + + custom_field { + name = "cf_json" + type = "json" + value = jsonencode({ + stringvalue = "string" + boolvalue = false + dictionary = { + numbervalue = 5 + } + }) + } + + custom_field { + name = "cf_object" + type = "object" + value = 1 + } + + custom_field { + name = "cf_multi_object" + type = "multiobject" + value = jsonencode([ + 1, + 2 + ]) } } diff --git a/examples/resources/netbox_ipam_prefix/resource.tf b/examples/resources/netbox_ipam_prefix/resource.tf index 3e85518ba..c4fd92a55 100644 --- a/examples/resources/netbox_ipam_prefix/resource.tf +++ b/examples/resources/netbox_ipam_prefix/resource.tf @@ -37,7 +37,7 @@ resource "netbox_ipam_prefix" "prefix_test" { custom_field { name = "cf_selection" - type = "selection" + type = "select" value = "1" } @@ -48,9 +48,39 @@ resource "netbox_ipam_prefix" "prefix_test" { } custom_field { - name = "cf_multiple_selection" - type = "multiple" - value = "0,1" + name = "cf_multi_selection" + type = "multiselect" + value = jsonencode([ + "0", + "1" + ]) + } + + custom_field { + name = "cf_json" + type = "json" + value = jsonencode({ + stringvalue = "string" + boolvalue = false + dictionary = { + numbervalue = 5 + } + }) + } + + custom_field { + name = "cf_object" + type = "object" + value = 1 + } + + custom_field { + name = "cf_multi_object" + type = "multiobject" + value = jsonencode([ + 1, + 2 + ]) } } diff --git a/examples/resources/netbox_ipam_service/resource.tf b/examples/resources/netbox_ipam_service/resource.tf index 2dd882740..9c7cb9dd0 100644 --- a/examples/resources/netbox_ipam_service/resource.tf +++ b/examples/resources/netbox_ipam_service/resource.tf @@ -37,7 +37,7 @@ resource "netbox_ipam_service" "service_test" { custom_field { name = "cf_selection" - type = "selection" + type = "select" value = "1" } @@ -48,8 +48,38 @@ resource "netbox_ipam_service" "service_test" { } custom_field { - name = "cf_multiple_selection" - type = "multiple" - value = "0,1" + name = "cf_multi_selection" + type = "multiselect" + value = jsonencode([ + "0", + "1" + ]) + } + + custom_field { + name = "cf_json" + type = "json" + value = jsonencode({ + stringvalue = "string" + boolvalue = false + dictionary = { + numbervalue = 5 + } + }) + } + + custom_field { + name = "cf_object" + type = "object" + value = 1 + } + + custom_field { + name = "cf_multi_object" + type = "multiobject" + value = jsonencode([ + 1, + 2 + ]) } } diff --git a/examples/resources/netbox_ipam_vlan/resource.tf b/examples/resources/netbox_ipam_vlan/resource.tf index d100fba23..3759aa423 100644 --- a/examples/resources/netbox_ipam_vlan/resource.tf +++ b/examples/resources/netbox_ipam_vlan/resource.tf @@ -38,7 +38,7 @@ resource "netbox_ipam_vlan" "vlan_test" { custom_field { name = "cf_selection" - type = "selection" + type = "select" value = "1" } @@ -49,8 +49,38 @@ resource "netbox_ipam_vlan" "vlan_test" { } custom_field { - name = "cf_multiple_selection" - type = "multiple" - value = "0,1" + name = "cf_multi_selection" + type = "multiselect" + value = jsonencode([ + "0", + "1" + ]) + } + + custom_field { + name = "cf_json" + type = "json" + value = jsonencode({ + stringvalue = "string" + boolvalue = false + dictionary = { + numbervalue = 5 + } + }) + } + + custom_field { + name = "cf_object" + type = "object" + value = 1 + } + + custom_field { + name = "cf_multi_object" + type = "multiobject" + value = jsonencode([ + 1, + 2 + ]) } } diff --git a/examples/resources/netbox_tenancy_contact/resource.tf b/examples/resources/netbox_tenancy_contact/resource.tf index b775e318a..32e5a9732 100644 --- a/examples/resources/netbox_tenancy_contact/resource.tf +++ b/examples/resources/netbox_tenancy_contact/resource.tf @@ -38,7 +38,7 @@ resource "netbox_tenancy_contact" "contact_test" { custom_field { name = "cf_selection" - type = "selection" + type = "select" value = "1" } @@ -49,8 +49,38 @@ resource "netbox_tenancy_contact" "contact_test" { } custom_field { - name = "cf_multiple_selection" - type = "multiple" - value = "0,1" + name = "cf_multi_selection" + type = "multiselect" + value = jsonencode([ + "0", + "1" + ]) + } + + custom_field { + name = "cf_json" + type = "json" + value = jsonencode({ + stringvalue = "string" + boolvalue = false + dictionary = { + numbervalue = 5 + } + }) + } + + custom_field { + name = "cf_object" + type = "object" + value = 1 + } + + custom_field { + name = "cf_multi_object" + type = "multiobject" + value = jsonencode([ + 1, + 2 + ]) } } diff --git a/examples/resources/netbox_tenancy_contact_group/resource.tf b/examples/resources/netbox_tenancy_contact_group/resource.tf index 9762168a4..84a8d7dfd 100644 --- a/examples/resources/netbox_tenancy_contact_group/resource.tf +++ b/examples/resources/netbox_tenancy_contact_group/resource.tf @@ -35,7 +35,7 @@ resource "netbox_tenancy_contact_group" "contact_group_test" { custom_field { name = "cf_selection" - type = "selection" + type = "select" value = "1" } @@ -46,8 +46,38 @@ resource "netbox_tenancy_contact_group" "contact_group_test" { } custom_field { - name = "cf_multiple_selection" - type = "multiple" - value = "0,1" + name = "cf_multi_selection" + type = "multiselect" + value = jsonencode([ + "0", + "1" + ]) + } + + custom_field { + name = "cf_json" + type = "json" + value = jsonencode({ + stringvalue = "string" + boolvalue = false + dictionary = { + numbervalue = 5 + } + }) + } + + custom_field { + name = "cf_object" + type = "object" + value = 1 + } + + custom_field { + name = "cf_multi_object" + type = "multiobject" + value = jsonencode([ + 1, + 2 + ]) } } diff --git a/examples/resources/netbox_tenancy_contact_role/resource.tf b/examples/resources/netbox_tenancy_contact_role/resource.tf index b749c435a..a55192929 100644 --- a/examples/resources/netbox_tenancy_contact_role/resource.tf +++ b/examples/resources/netbox_tenancy_contact_role/resource.tf @@ -34,7 +34,7 @@ resource "netbox_tenancy_contact_role" "contact_role_test" { custom_field { name = "cf_selection" - type = "selection" + type = "select" value = "1" } @@ -45,8 +45,38 @@ resource "netbox_tenancy_contact_role" "contact_role_test" { } custom_field { - name = "cf_multiple_selection" - type = "multiple" - value = "0,1" + name = "cf_multi_selection" + type = "multiselect" + value = jsonencode([ + "0", + "1" + ]) + } + + custom_field { + name = "cf_json" + type = "json" + value = jsonencode({ + stringvalue = "string" + boolvalue = false + dictionary = { + numbervalue = 5 + } + }) + } + + custom_field { + name = "cf_object" + type = "object" + value = 1 + } + + custom_field { + name = "cf_multi_object" + type = "multiobject" + value = jsonencode([ + 1, + 2 + ]) } } diff --git a/examples/resources/netbox_tenancy_tenant/resource.tf b/examples/resources/netbox_tenancy_tenant/resource.tf index 5571c3b47..fe6e1c65b 100644 --- a/examples/resources/netbox_tenancy_tenant/resource.tf +++ b/examples/resources/netbox_tenancy_tenant/resource.tf @@ -36,7 +36,7 @@ resource "netbox_tenancy_tenant" "tenant_test" { custom_field { name = "cf_selection" - type = "selection" + type = "select" value = "1" } @@ -47,8 +47,38 @@ resource "netbox_tenancy_tenant" "tenant_test" { } custom_field { - name = "cf_multiple_selection" - type = "multiple" - value = "0,1" + name = "cf_multi_selection" + type = "multiselect" + value = jsonencode([ + "0", + "1" + ]) + } + + custom_field { + name = "cf_json" + type = "json" + value = jsonencode({ + stringvalue = "string" + boolvalue = false + dictionary = { + numbervalue = 5 + } + }) + } + + custom_field { + name = "cf_object" + type = "object" + value = 1 + } + + custom_field { + name = "cf_multi_object" + type = "multiobject" + value = jsonencode([ + 1, + 2 + ]) } } diff --git a/examples/resources/netbox_virtualization_interface/resource.tf b/examples/resources/netbox_virtualization_interface/resource.tf index d0b4f8a93..ec686474d 100644 --- a/examples/resources/netbox_virtualization_interface/resource.tf +++ b/examples/resources/netbox_virtualization_interface/resource.tf @@ -31,7 +31,7 @@ resource "netbox_virtualization_interface" "interface_test" { custom_field { name = "cf_selection" - type = "selection" + type = "select" value = "1" } @@ -42,8 +42,38 @@ resource "netbox_virtualization_interface" "interface_test" { } custom_field { - name = "cf_multiple_selection" - type = "multiple" - value = "0,1" + name = "cf_multi_selection" + type = "multiselect" + value = jsonencode([ + "0", + "1" + ]) + } + + custom_field { + name = "cf_json" + type = "json" + value = jsonencode({ + stringvalue = "string" + boolvalue = false + dictionary = { + numbervalue = 5 + } + }) + } + + custom_field { + name = "cf_object" + type = "object" + value = 1 + } + + custom_field { + name = "cf_multi_object" + type = "multiobject" + value = jsonencode([ + 1, + 2 + ]) } } diff --git a/examples/resources/netbox_virtualization_vm/resource.tf b/examples/resources/netbox_virtualization_vm/resource.tf index d2aeb0704..44eb0845a 100644 --- a/examples/resources/netbox_virtualization_vm/resource.tf +++ b/examples/resources/netbox_virtualization_vm/resource.tf @@ -43,7 +43,7 @@ resource "netbox_virtualization_vm" "vm_test" { custom_field { name = "cf_selection" - type = "selection" + type = "select" value = "1" } @@ -54,8 +54,38 @@ resource "netbox_virtualization_vm" "vm_test" { } custom_field { - name = "cf_multiple_selection" - type = "multiple" - value = "0,1" + name = "cf_multi_selection" + type = "multiselect" + value = jsonencode([ + "0", + "1" + ]) + } + + custom_field { + name = "cf_json" + type = "json" + value = jsonencode({ + stringvalue = "string" + boolvalue = false + dictionary = { + numbervalue = 5 + } + }) + } + + custom_field { + name = "cf_object" + type = "object" + value = 1 + } + + custom_field { + name = "cf_multi_object" + type = "multiobject" + value = jsonencode([ + 1, + 2 + ]) } } diff --git a/netbox/resource_netbox_ipam_aggregate.go b/netbox/resource_netbox_ipam_aggregate.go index e9a7af617..5b3141e0c 100644 --- a/netbox/resource_netbox_ipam_aggregate.go +++ b/netbox/resource_netbox_ipam_aggregate.go @@ -38,32 +38,7 @@ func resourceNetboxIpamAggregate() *schema.Resource { Computed: true, Description: "Date when this aggregate was created.", }, - "custom_field": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - Description: "Name of the existing custom field.", - }, - "type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{"text", "integer", "boolean", - "date", "url", "selection", "multiple"}, false), - Description: "Type of the existing custom field (text, integer, boolean, url, selection, multiple).", - }, - "value": { - Type: schema.TypeString, - Required: true, - Description: "Value of the existing custom field.", - }, - }, - }, - Description: "Existing custom fields to associate to this aggregate (ipam module).", - }, + "custom_field": &customFieldSchema, "date_added": { Type: schema.TypeString, Optional: true, diff --git a/netbox/resource_netbox_ipam_ip_addresses.go b/netbox/resource_netbox_ipam_ip_addresses.go index 0da94a37e..9bbcd0c21 100644 --- a/netbox/resource_netbox_ipam_ip_addresses.go +++ b/netbox/resource_netbox_ipam_ip_addresses.go @@ -51,32 +51,7 @@ func resourceNetboxIpamIPAddresses() *schema.Resource { Computed: true, Description: "The content type of this IP address (ipam module).", }, - "custom_field": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - Description: "Name of the existing custom field.", - }, - "type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{"text", "integer", "boolean", - "date", "url", "selection", "multiple"}, false), - Description: "Type of the existing custom field (text, integer, boolean, url, selection, multiple).", - }, - "value": { - Type: schema.TypeString, - Required: true, - Description: "Value of the existing custom field.", - }, - }, - }, - Description: "Existing custom fields to associate to this IP address (ipam module).", - }, + "custom_field": &customFieldSchema, "description": { Type: schema.TypeString, Optional: true, diff --git a/netbox/resource_netbox_ipam_ip_range.go b/netbox/resource_netbox_ipam_ip_range.go index 90dd1dd75..40142a9bd 100644 --- a/netbox/resource_netbox_ipam_ip_range.go +++ b/netbox/resource_netbox_ipam_ip_range.go @@ -30,32 +30,7 @@ func resourceNetboxIpamIPRange() *schema.Resource { Computed: true, Description: "The content type of this prefix (ipam module).", }, - "custom_field": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - Description: "Name of the existing custom field.", - }, - "type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{"text", "integer", "boolean", - "date", "url", "selection", "multiple"}, false), - Description: "Type of the existing custom field (text, integer, boolean, url, selection, multiple).", - }, - "value": { - Type: schema.TypeString, - Required: true, - Description: "Value of the existing custom field.", - }, - }, - }, - Description: "Existing custom fields to associate to this prefix (ipam module).", - }, + "custom_field": &customFieldSchema, "description": { Type: schema.TypeString, Optional: true, diff --git a/netbox/resource_netbox_ipam_prefix.go b/netbox/resource_netbox_ipam_prefix.go index 7eddeba82..267eb7cdb 100644 --- a/netbox/resource_netbox_ipam_prefix.go +++ b/netbox/resource_netbox_ipam_prefix.go @@ -30,32 +30,7 @@ func resourceNetboxIpamPrefix() *schema.Resource { Computed: true, Description: "The content type of this prefix (ipam module).", }, - "custom_field": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - Description: "Name of the existing custom field.", - }, - "type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{"text", "integer", "boolean", - "date", "url", "selection", "multiple"}, false), - Description: "Type of the existing custom field (text, integer, boolean, url, selection, multiple).", - }, - "value": { - Type: schema.TypeString, - Required: true, - Description: "Value of the existing custom field.", - }, - }, - }, - Description: "Existing custom fields to associate to this prefix (ipam module).", - }, + "custom_field": &customFieldSchema, "description": { Type: schema.TypeString, Optional: true, diff --git a/netbox/resource_netbox_ipam_service.go b/netbox/resource_netbox_ipam_service.go index bb7253210..2a29b1dc2 100644 --- a/netbox/resource_netbox_ipam_service.go +++ b/netbox/resource_netbox_ipam_service.go @@ -30,32 +30,7 @@ func resourceNetboxIpamService() *schema.Resource { Computed: true, Description: "The content type of this service (ipam module).", }, - "custom_field": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - Description: "Name of the existing custom field.", - }, - "type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{"text", "integer", "boolean", - "date", "url", "selection", "multiple"}, false), - Description: "Type of the existing custom field (text, integer, boolean, url, selection, multiple).", - }, - "value": { - Type: schema.TypeString, - Required: true, - Description: "Value of the existing custom field.", - }, - }, - }, - Description: "Existing custom fields to associate to this service (ipam module).", - }, + "custom_field": &customFieldSchema, "description": { Type: schema.TypeString, Optional: true, diff --git a/netbox/resource_netbox_ipam_vlan.go b/netbox/resource_netbox_ipam_vlan.go index 882cd580e..525141239 100644 --- a/netbox/resource_netbox_ipam_vlan.go +++ b/netbox/resource_netbox_ipam_vlan.go @@ -30,32 +30,7 @@ func resourceNetboxIpamVlan() *schema.Resource { Computed: true, Description: "The content type of this vlan (ipam module).", }, - "custom_field": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - Description: "Name of the existing custom field.", - }, - "type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{"text", "integer", "boolean", - "date", "url", "selection", "multiple"}, false), - Description: "Type of the existing custom field (text, integer, boolean, url, selection, multiple).", - }, - "value": { - Type: schema.TypeString, - Required: true, - Description: "Value of the existing custom field.", - }, - }, - }, - Description: "Existing custom fields to associate to this vlan (ipam module).", - }, + "custom_field": &customFieldSchema, "description": { Type: schema.TypeString, Optional: true, @@ -285,6 +260,11 @@ func resourceNetboxIpamVlanRead(ctx context.Context, d *schema.ResourceData, func resourceNetboxIpamVlanUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { client := m.(*netboxclient.NetBoxAPI) + dropFields := []string{ + "created", + "last_updated", + } + emptyFields := make(map[string]interface{}) params := &models.WritableVLAN{} // Required parameters @@ -313,6 +293,8 @@ func resourceNetboxIpamVlanUpdate(ctx context.Context, d *schema.ResourceData, if groupID != 0 { params.Group = &groupID } + } else { + dropFields = append(dropFields, "group") } if d.HasChange("role_id") { @@ -353,7 +335,7 @@ func resourceNetboxIpamVlanUpdate(ctx context.Context, d *schema.ResourceData, resource.SetID(resourceID) - _, err = client.Ipam.IpamVlansPartialUpdate(resource, nil) + _, err = client.Ipam.IpamVlansPartialUpdate(resource, nil, newRequestModifierOperation(emptyFields, dropFields)) if err != nil { return diag.FromErr(err) } diff --git a/netbox/resource_netbox_tenancy_contact.go b/netbox/resource_netbox_tenancy_contact.go index a618374fa..db3e48091 100644 --- a/netbox/resource_netbox_tenancy_contact.go +++ b/netbox/resource_netbox_tenancy_contact.go @@ -51,32 +51,7 @@ func resourceNetboxTenancyContact() *schema.Resource { Computed: true, Description: "The content type of this contact (tenancy module).", }, - "custom_field": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - Description: "Name of the existing custom field.", - }, - "type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{"text", "integer", "boolean", - "date", "url", "selection", "multiple"}, false), - Description: "Type of the existing custom field (text, integer, boolean, url, selection, multiple).", - }, - "value": { - Type: schema.TypeString, - Required: true, - Description: "Value of the existing custom field.", - }, - }, - }, - Description: "Existing custom fields to associate to this contact (tenancy module).", - }, + "custom_field": &customFieldSchema, "email": { Type: schema.TypeString, Optional: true, @@ -285,6 +260,11 @@ func resourceNetboxTenancyContactRead(ctx context.Context, d *schema.ResourceDat func resourceNetboxTenancyContactUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { client := m.(*netboxclient.NetBoxAPI) + dropFields := []string{ + "created", + "last_updated", + } + emptyFields := make(map[string]interface{}) params := &models.WritableContact{} // Required parameters @@ -314,6 +294,8 @@ func resourceNetboxTenancyContactUpdate(ctx context.Context, d *schema.ResourceD } else { params.Group = &groupID } + } else { + dropFields = append(dropFields, "group") } if d.HasChange("custom_field") { @@ -358,7 +340,7 @@ func resourceNetboxTenancyContactUpdate(ctx context.Context, d *schema.ResourceD resource.SetID(resourceID) - _, err = client.Tenancy.TenancyContactsPartialUpdate(resource, nil) + _, err = client.Tenancy.TenancyContactsPartialUpdate(resource, nil, newRequestModifierOperation(emptyFields, dropFields)) if err != nil { return diag.FromErr(err) } diff --git a/netbox/resource_netbox_tenancy_contact_group.go b/netbox/resource_netbox_tenancy_contact_group.go index f7c74424e..87096eef8 100644 --- a/netbox/resource_netbox_tenancy_contact_group.go +++ b/netbox/resource_netbox_tenancy_contact_group.go @@ -31,32 +31,7 @@ func resourceNetboxTenancyContactGroup() *schema.Resource { Computed: true, Description: "The content type of this contact group (tenancy module).", }, - "custom_field": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - Description: "Name of the existing custom field.", - }, - "type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{"text", "integer", "boolean", - "date", "url", "selection", "multiple"}, false), - Description: "Type of the existing custom field (text, integer, boolean, url, selection, multiple).", - }, - "value": { - Type: schema.TypeString, - Required: true, - Description: "Value of the existing custom field.", - }, - }, - }, - Description: "Existing custom fields to associate to this contact group (tenancy module).", - }, + "custom_field": &customFieldSchema, "description": { Type: schema.TypeString, Optional: true, @@ -221,7 +196,9 @@ func resourceNetboxTenancyContactGroupUpdate(ctx context.Context, d *schema.Reso params.Slug = &slug parentID := int64(d.Get("parent_id").(int)) - params.Parent = &parentID + if parentID != 0 { + params.Parent = &parentID + } if d.HasChange("custom_field") { stateCustomFields, resourceCustomFields := d.GetChange("custom_field") diff --git a/netbox/resource_netbox_tenancy_contact_role.go b/netbox/resource_netbox_tenancy_contact_role.go index d59332c7f..24e95e16f 100644 --- a/netbox/resource_netbox_tenancy_contact_role.go +++ b/netbox/resource_netbox_tenancy_contact_role.go @@ -31,32 +31,7 @@ func resourceNetboxTenancyContactRole() *schema.Resource { Computed: true, Description: "The content type of this contact role (tenancy module).", }, - "custom_field": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - Description: "Name of the existing custom field.", - }, - "type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{"text", "integer", "boolean", - "date", "url", "selection", "multiple"}, false), - Description: "Type of the existing custom field (text, integer, boolean, url, selection, multiple).", - }, - "value": { - Type: schema.TypeString, - Required: true, - Description: "Value of the existing custom field.", - }, - }, - }, - Description: "Existing custom fields to associate to this contact role (tenancy module).", - }, + "custom_field": &customFieldSchema, "description": { Type: schema.TypeString, Optional: true, diff --git a/netbox/resource_netbox_tenancy_tenant.go b/netbox/resource_netbox_tenancy_tenant.go index fdea99a45..c59c5e83b 100644 --- a/netbox/resource_netbox_tenancy_tenant.go +++ b/netbox/resource_netbox_tenancy_tenant.go @@ -37,32 +37,7 @@ func resourceNetboxTenancyTenant() *schema.Resource { Computed: true, Description: "The content type of this tenant (tenancy module).", }, - "custom_field": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - Description: "Name of the existing custom field.", - }, - "type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{"text", "integer", "boolean", - "date", "url", "selection", "multiple"}, false), - Description: "Type of the existing custom field (text, integer, boolean, url, selection, multiple).", - }, - "value": { - Type: schema.TypeString, - Required: true, - Description: "Value of the existing custom field.", - }, - }, - }, - Description: "Existing custom fields to associate to this tenant (tenancy module).", - }, + "custom_field": &customFieldSchema, "description": { Type: schema.TypeString, Optional: true, diff --git a/netbox/resource_netbox_virtualization_interface.go b/netbox/resource_netbox_virtualization_interface.go index 7e16fea5f..db75a9e2d 100644 --- a/netbox/resource_netbox_virtualization_interface.go +++ b/netbox/resource_netbox_virtualization_interface.go @@ -31,32 +31,7 @@ func resourceNetboxVirtualizationInterface() *schema.Resource { Computed: true, Description: "The content type of this interface (virtualization module).", }, - "custom_field": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - Description: "Name of the existing custom field.", - }, - "type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{"text", "integer", "boolean", - "date", "url", "selection", "multiple"}, false), - Description: "Type of the existing custom field (text, integer, boolean, url, selection, multiple).", - }, - "value": { - Type: schema.TypeString, - Required: true, - Description: "Value of the existing custom field.", - }, - }, - }, - Description: "Existing custom fields to associate to this interface (virtualization module).", - }, + "custom_field": &customFieldSchema, "description": { Type: schema.TypeString, Optional: true, diff --git a/netbox/resource_netbox_virtualization_vm.go b/netbox/resource_netbox_virtualization_vm.go index 45a02e3be..4f079022e 100644 --- a/netbox/resource_netbox_virtualization_vm.go +++ b/netbox/resource_netbox_virtualization_vm.go @@ -45,32 +45,7 @@ func resourceNetboxVirtualizationVM() *schema.Resource { Computed: true, Description: "The content type of this VM (virtualization module).", }, - "custom_field": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - Description: "Name of the existing custom field.", - }, - "type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{"text", "integer", "boolean", - "date", "url", "selection", "multiple"}, false), - Description: "Type of the existing custom field (text, integer, boolean, url, selection, multiple).", - }, - "value": { - Type: schema.TypeString, - Required: true, - Description: "Value of the existing custom field.", - }, - }, - }, - Description: "Existing custom fields to associate to this VM (virtualization module).", - }, + "custom_field": &customFieldSchema, "disk": { Type: schema.TypeInt, Optional: true, diff --git a/netbox/util.go b/netbox/util.go index 1e52ebe14..6a86fc9f2 100644 --- a/netbox/util.go +++ b/netbox/util.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" netboxclient "github.com/smutel/go-netbox/v3/netbox/client" "github.com/smutel/go-netbox/v3/netbox/client/ipam" "github.com/smutel/go-netbox/v3/netbox/client/virtualization" @@ -21,6 +23,38 @@ const VMInterfaceType string = "virtualization.vminterface" // Boolean string for custom field const CustomFieldBoolean = "boolean" +const CustomFieldJSON = "json" +const CustomFieldMultiSelectLegacy = "multiple" +const CustomFieldMultiSelect = "multiselect" +const CustomFieldObject = "object" +const CustomFieldMultiObject = "multiobject" + +var customFieldSchema = schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + Description: "Name of the existing custom field.", + }, + "type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{"text", "longtext", "integer", CustomFieldBoolean, + "date", "url", CustomFieldJSON, "select", CustomFieldMultiSelect, CustomFieldObject, CustomFieldMultiObject, CustomFieldMultiSelectLegacy, "selection"}, false), + Description: "Type of the existing custom field (text, longtext, integer, boolean, date, url, json, select, multiselect, object, multiobject, selection (deprecated), multiple(deprecated)).", + }, + "value": { + Type: schema.TypeString, + Required: true, + Description: "Value of the existing custom field.", + }, + }, + }, + Description: "Existing custom fields to associate to this ressource.", +} func expandToInt64Slice(v []interface{}) []int64 { s := make([]int64, len(v)) @@ -200,6 +234,38 @@ func convertArrayInterfaceString(arrayInterface []interface{}) string { return result } +func convertArrayInterfaceJSONString(arrayInterface []interface{}) string { + var arrayString []interface{} + + for _, item := range arrayInterface { + switch v := item.(type) { + case map[string]interface{}: + arrayString = append(arrayString, string(v["id"].(json.Number))) + default: + arrayString = append(arrayString, v) + } + } + + if len(arrayString) > 1 { + switch arrayString[0].(type) { + case json.Number: + sort.Slice(arrayString, func(i, j int) bool { + return arrayString[i].(json.Number) < arrayString[j].(json.Number) + }) + case string: + sort.Slice(arrayString, func(i, j int) bool { + return arrayString[i].(string) < arrayString[j].(string) + }) + default: + panic("") + } + } + jsonValue, _ := json.Marshal(arrayString) + result := string(jsonValue) + + return result +} + // Pick the custom fields in the state file and update values with data from API func updateCustomFieldsFromAPI(stateCustomFields, customFields interface{}) []map[string]string { var tfCms []map[string]string @@ -215,20 +281,25 @@ func updateCustomFieldsFromAPI(stateCustomFields, customFields interface{}) []ma cm["name"] = key cm["type"] = stateCustomField.(map[string]interface{})["type"].(string) - if value != nil { + if value != nil && cm["type"] == CustomFieldJSON { + jsonValue, _ := json.Marshal(value) + cm["value"] = string(jsonValue) + } else if value != nil { switch v := value.(type) { case []interface{}: - strValue = convertArrayInterfaceString(v) + if cm["type"] == CustomFieldMultiSelectLegacy { + strValue = convertArrayInterfaceString(v) + } else if cm["type"] == CustomFieldObject { + strValue = string(value.([]interface{})[0].(map[string]interface{})["id"].(json.Number)) + } else { + strValue = convertArrayInterfaceJSONString(v) + } + case map[string]interface{}: + strValue = string(v["id"].(json.Number)) default: strValue = fmt.Sprintf("%v", v) } - if strValue == "1" && cm["type"] == CustomFieldBoolean { - strValue = "true" - } else if strValue == "0" && cm["type"] == CustomFieldBoolean { - strValue = "false" - } - cm["value"] = strValue } else { cm["value"] = "" @@ -260,20 +331,51 @@ func convertCustomFieldsFromTerraformToAPI(stateCustomFields []interface{}, cust cfValue := customField["value"].(string) if len(cfValue) > 0 { - if cfType == "integer" { + switch cfType { + case "integer": cfValueInt, _ := strconv.Atoi(cfValue) toReturn[cfName] = cfValueInt - } else if cfType == CustomFieldBoolean { + case CustomFieldBoolean: if cfValue == "true" { toReturn[cfName] = true } else if cfValue == "false" { toReturn[cfName] = false } - } else if cfType == "multiple" { + case CustomFieldMultiSelectLegacy: cfValueArray := strings.Split(cfValue, ",") sort.Strings(cfValueArray) toReturn[cfName] = cfValueArray - } else { + case CustomFieldJSON: + jsonMap := make(map[string]interface{}) + err := json.Unmarshal([]byte(cfValue), &jsonMap) + if err != nil { + continue + } + toReturn[cfName] = jsonMap + case CustomFieldMultiSelect: + var jsonList []interface{} + err := json.Unmarshal([]byte(cfValue), &jsonList) + if err != nil { + continue + } + sort.Slice(jsonList, func(i, j int) bool { + return jsonList[i].(string) < jsonList[j].(string) + }) + toReturn[cfName] = jsonList + case CustomFieldObject: + cfValueInt, _ := strconv.Atoi(cfValue) + toReturn[cfName] = []int{cfValueInt} + case CustomFieldMultiObject: + var jsonList []interface{} + err := json.Unmarshal([]byte(cfValue), &jsonList) + if err != nil { + continue + } + sort.Slice(jsonList, func(i, j int) bool { + return jsonList[i].(string) < jsonList[j].(string) + }) + toReturn[cfName] = jsonList + default: toReturn[cfName] = cfValue } } else {