From 87fbc924c2d31dcfa3f37f63b6ad22adad95c7d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Nie=C3=9F?= Date: Sun, 30 Oct 2022 21:03:01 +0100 Subject: [PATCH] feat: Add netbox_extras_custom_field resource --- .../netbox_extras_custom_field/resource.tf | 148 ++++++ .../resource_netbox_extras_custom_field.go | 422 ++++++++++++++++++ ...netbox_extras_custom_field_boolean_test.go | 119 +++++ ...ce_netbox_extras_custom_field_date_test.go | 119 +++++ ...netbox_extras_custom_field_integer_test.go | 121 +++++ ...ce_netbox_extras_custom_field_json_test.go | 125 ++++++ ...etbox_extras_custom_field_longtext_test.go | 119 +++++ ...ox_extras_custom_field_multiobject_test.go | 129 ++++++ ...ox_extras_custom_field_multiselect_test.go | 123 +++++ ..._netbox_extras_custom_field_object_test.go | 129 ++++++ ..._netbox_extras_custom_field_select_test.go | 122 +++++ ...ce_netbox_extras_custom_field_text_test.go | 119 +++++ ...rce_netbox_extras_custom_field_url_test.go | 119 +++++ netbox/internal/util/util.go | 8 + netbox/provider.go | 1 + 15 files changed, 1923 insertions(+) create mode 100644 examples/resources/netbox_extras_custom_field/resource.tf create mode 100644 netbox/extras/resource_netbox_extras_custom_field.go create mode 100644 netbox/extras/resource_netbox_extras_custom_field_boolean_test.go create mode 100644 netbox/extras/resource_netbox_extras_custom_field_date_test.go create mode 100644 netbox/extras/resource_netbox_extras_custom_field_integer_test.go create mode 100644 netbox/extras/resource_netbox_extras_custom_field_json_test.go create mode 100644 netbox/extras/resource_netbox_extras_custom_field_longtext_test.go create mode 100644 netbox/extras/resource_netbox_extras_custom_field_multiobject_test.go create mode 100644 netbox/extras/resource_netbox_extras_custom_field_multiselect_test.go create mode 100644 netbox/extras/resource_netbox_extras_custom_field_object_test.go create mode 100644 netbox/extras/resource_netbox_extras_custom_field_select_test.go create mode 100644 netbox/extras/resource_netbox_extras_custom_field_text_test.go create mode 100644 netbox/extras/resource_netbox_extras_custom_field_url_test.go diff --git a/examples/resources/netbox_extras_custom_field/resource.tf b/examples/resources/netbox_extras_custom_field/resource.tf new file mode 100644 index 000000000..0704e8f5a --- /dev/null +++ b/examples/resources/netbox_extras_custom_field/resource.tf @@ -0,0 +1,148 @@ +resource "netbox_extras_custom_field" "cf_text" { + name = "cf_text" + label = "CF Text" + type = "text" + content_types = [ + "dcim.site", + ] + + description = "Test text field" + weight = 50 + required = true + filter_logic = "exact" + default = "Default value" + validation_regex = "^.*$" +} + +resource "netbox_extras_custom_field" "cf_boolean" { + name = "cf_boolean" + label = "CF Boolean" + type = "boolean" + content_types = [ + "dcim.site", + ] + + description = "Test boolean field" + weight = 50 + filter_logic = "exact" + # Fixed in Netbox 3.3 + # required = true + # default = jsonencode(false) +} + +resource "netbox_extras_custom_field" "cf_integer" { + name = "cf_integer" + label = "CF Integer" + type = "integer" + content_types = [ + "dcim.site", + ] + + description = "Test integer field" + weight = 50 + filter_logic = "loose" + # Fixed in Netbox 3.3 + # required = true + # default = jsonencode(5) +} + +resource "netbox_extras_custom_field" "cf_select" { + name = "cf_select" + label = "CF Select" + type = "select" + content_types = [ + "dcim.site", + ] + + choices = [ + "choice 1", + "choice 2", + ] + + description = "Test select field" + weight = 50 + filter_logic = "loose" + required = true + default = "choice 1" +} + +resource "netbox_extras_custom_field" "cf_multi_select" { + name = "cf_mulit_select" + label = "CF Multiselect" + type = "multiselect" + content_types = [ + "dcim.site", + ] + + choices = [ + "choice 1", + "choice 2", + ] + + description = "Test multiselect field" + weight = 50 + filter_logic = "loose" + # Fixed in netbox 3.3 + # required = true + # default = jsonencode([ + # "choice 1", + # ]) +} + +resource "netbox_extras_custom_field" "cf_object" { + name = "cf_object" + label = "CF object" + type = "object" + content_types = [ + "dcim.site", + ] + + object_type = "dcim.platform" + description = "Test object field" + weight = 50 + filter_logic = "loose" + # Fixed in netbox 3.3 + # required = true + #default = jsonencode(netbox_dcim_platform.test.id) +} + +resource "netbox_extras_custom_field" "cf_multi_object" { + name = "cf_mulit_object" + label = "CF Multiobject" + type = "multiobject" + content_types = [ + "dcim.site", + ] + + object_type = "dcim.platform" + description = "Test multiobject field" + weight = 50 + filter_logic = "loose" + # Fixed in netbox 3.3 + # required = true + # default = jsonencode([ + # netbox_dcim_platform.test.id, + # ]) +} + +resource "netbox_extras_custom_field" "cf_json" { + name = "cf_json" + label = "CF Json" + type = "json" + content_types = [ + "dcim.site", + ] + + description = "Test multiobject field" + weight = 50 + filter_logic = "loose" + # Fixed in netbox 3.3 + # required = true + #default = jsonencode({ + # bool = false + # number = 1.5 + # dict = { + # text = "Some text"} + # } + #}) +} diff --git a/netbox/extras/resource_netbox_extras_custom_field.go b/netbox/extras/resource_netbox_extras_custom_field.go new file mode 100644 index 000000000..e969a6d98 --- /dev/null +++ b/netbox/extras/resource_netbox_extras_custom_field.go @@ -0,0 +1,422 @@ +package extras + +import ( + "context" + "strconv" + + "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" + netboxclient "github.com/smutel/go-netbox/v3/netbox/client" + "github.com/smutel/go-netbox/v3/netbox/client/extras" + "github.com/smutel/go-netbox/v3/netbox/models" + "github.com/smutel/terraform-provider-netbox/v4/netbox/internal/requestmodifier" + "github.com/smutel/terraform-provider-netbox/v4/netbox/internal/util" +) + +func ResourceNetboxExtrasCustomField() *schema.Resource { + return &schema.Resource{ + Description: "Manage a custom field (extras module) within Netbox. *CAVEAT*: This module is mostly intended for testing. Be careful when changing custom fields in production.", + CreateContext: resourceNetboxExtrasCustomFieldCreate, + ReadContext: resourceNetboxExtrasCustomFieldRead, + UpdateContext: resourceNetboxExtrasCustomFieldUpdate, + DeleteContext: resourceNetboxExtrasCustomFieldDelete, + Exists: resourceNetboxExtrasCustomFieldExists, + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Schema: map[string]*schema.Schema{ + "choices": { + Type: schema.TypeSet, + Optional: true, + Default: nil, + Description: "Avaialbe choices for selection fields.", + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringLenBetween(1, 100), + }, + }, + "content_type": { + Type: schema.TypeString, + Computed: true, + Description: "The content type of this custom field (extras module).", + }, + "content_types": { + Type: schema.TypeSet, + Required: true, + Description: "The content types this field should be assigned to.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "created": { + Type: schema.TypeString, + Computed: true, + Description: "Date when this custom field was created.", + }, + "data_type": { + Type: schema.TypeString, + Computed: true, + Description: "The data type of this custom field.", + }, + "default": { + Type: schema.TypeString, + Optional: true, + Description: "The default value for this custom field. Encoded as JSON.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Default: nil, + ValidateFunc: validation.StringLenBetween(1, 200), + Description: "The description of this custom field.", + }, + "filter_logic": { + Type: schema.TypeString, + Optional: true, + Default: "loose", + ValidateFunc: validation.StringInSlice([]string{"disabled", "loose", "exact"}, false), + Description: "The filter logic for this custom field. Allowed values: \"loose\" (default), \"exact\", \"disabled\"", + }, + "label": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the field as displayed to users (if not provided, the field's name will be used).", + }, + "last_updated": { + Type: schema.TypeString, + Computed: true, + Description: "Date when this custom field was last updated.", + }, + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 50), + Description: "The name of this custom field (extras module).", + }, + "object_type": { + Type: schema.TypeString, + Optional: true, + Description: "The object type for this custom field for object/multiobject fields", + }, + "required": { + Type: schema.TypeBool, + Optional: true, + Description: "If true, this field is required when creating new objects or editing an existing object.", + }, + "type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + "text", + "longtext", + "integer", + "boolean", + "date", + "url", + "json", + "select", + "multiselect", + "object", + "multiobject", + }, false), + Description: "Type of the custom field (text, longtext, integer, boolean, url, json, select, multiselect, object, multiobject).", + }, + "url": { + Type: schema.TypeString, + Computed: true, + Description: "The link to this custom field (extras module).", + }, + "validation_maximum": { + Type: schema.TypeInt, + Optional: true, + Description: "Maximum allowed value (for numeric fields)", + }, + "validation_minimum": { + Type: schema.TypeInt, + Optional: true, + Description: "Minimum allowed value (for numeric fields)", + }, + "validation_regex": { + Type: schema.TypeString, + Optional: true, + Description: "Regular expression to enforce on text field values. Use ^ and $ to force matching of entire string. For example, ^[A-Z]{3}$ will limit values to exactly three uppercase letters.", + }, + "weight": { + Type: schema.TypeInt, + Optional: true, + Default: 100, + Description: "Fields with higher weights appear lower in a form.", + }, + }, + } +} + +var customFieldRequiredFields = []string{ + "created", + "last_updated", + "name", + "slug", + "tags", + "content_types", +} + +func resourceNetboxExtrasCustomFieldCreate(ctx context.Context, d *schema.ResourceData, + m interface{}) diag.Diagnostics { + client := m.(*netboxclient.NetBoxAPI) + + name := d.Get("name").(string) + defaultstring := d.Get("default").(string) + validationMaximum := int64(d.Get("validation_maximum").(int)) + var validationMaximumPtr *int64 + if validationMaximum != 0 { + validationMaximumPtr = &validationMaximum + } else { + validationMaximumPtr = nil + } + validationMinimum := int64(d.Get("validation_minimum").(int)) + var validationMinimumPtr *int64 + if validationMinimum != 0 { + validationMinimumPtr = &validationMinimum + } else { + validationMinimumPtr = nil + } + weight := int64(d.Get("weight").(int)) + + newResource := &models.WritableCustomField{ + Choices: util.ToListofStrings(d.Get("choices").(*schema.Set).List()), + ContentTypes: util.ToListofStrings(d.Get("content_types").(*schema.Set).List()), + Default: &defaultstring, + Description: d.Get("description").(string), + FilterLogic: d.Get("filter_logic").(string), + Label: d.Get("label").(string), + Name: &name, + ObjectType: d.Get("object_type").(string), + Required: d.Get("required").(bool), + Type: d.Get("type").(string), + ValidationMaximum: validationMaximumPtr, + ValidationMinimum: validationMinimumPtr, + ValidationRegex: d.Get("validation_regex").(string), + Weight: &weight, + } + + resource := extras.NewExtrasCustomFieldsCreateParams().WithData(newResource) + + resourceCreated, err := client.Extras.ExtrasCustomFieldsCreate(resource, nil) + if err != nil { + return diag.FromErr(err) + } + + d.SetId(strconv.FormatInt(resourceCreated.Payload.ID, 10)) + + return resourceNetboxExtrasCustomFieldRead(ctx, d, m) +} + +func resourceNetboxExtrasCustomFieldRead(ctx context.Context, d *schema.ResourceData, + m interface{}) diag.Diagnostics { + client := m.(*netboxclient.NetBoxAPI) + + resourceID := d.Id() + params := extras.NewExtrasCustomFieldsListParams().WithID(&resourceID) + resources, err := client.Extras.ExtrasCustomFieldsList(params, nil) + if err != nil { + return diag.FromErr(err) + } + + if len(resources.Payload.Results) != 1 { + d.SetId("") + return nil + } + + resource := resources.Payload.Results[0] + + if err = d.Set("choices", resource.Choices); err != nil { + return diag.FromErr(err) + } + if err = d.Set("content_type", util.ConvertURIContentType(resource.URL)); err != nil { + return diag.FromErr(err) + } + if err = d.Set("content_types", resource.ContentTypes); err != nil { + return diag.FromErr(err) + } + if err = d.Set("created", resource.Created.String()); err != nil { + return diag.FromErr(err) + } + if err = d.Set("data_type", resource.DataType); err != nil { + return diag.FromErr(err) + } + if err = d.Set("default", resource.Default); err != nil { + return diag.FromErr(err) + } + if err = d.Set("description", resource.Description); err != nil { + return diag.FromErr(err) + } + if err = d.Set("filter_logic", resource.FilterLogic.Value); err != nil { + return diag.FromErr(err) + } + if err = d.Set("label", resource.Label); err != nil { + return diag.FromErr(err) + } + if err = d.Set("last_updated", resource.LastUpdated.String()); err != nil { + return diag.FromErr(err) + } + if err = d.Set("name", resource.Name); err != nil { + return diag.FromErr(err) + } + if err = d.Set("object_type", resource.ObjectType); err != nil { + return diag.FromErr(err) + } + if err = d.Set("required", resource.Required); err != nil { + return diag.FromErr(err) + } + if err = d.Set("type", resource.Type.Value); err != nil { + return diag.FromErr(err) + } + if err = d.Set("url", resource.URL); err != nil { + return diag.FromErr(err) + } + if err = d.Set("validation_maximum", resource.ValidationMaximum); err != nil { + return diag.FromErr(err) + } + if err = d.Set("validation_minimum", resource.ValidationMinimum); err != nil { + return diag.FromErr(err) + } + if err = d.Set("validation_regex", resource.ValidationRegex); err != nil { + return diag.FromErr(err) + } + if err = d.Set("weight", resource.Weight); err != nil { + return diag.FromErr(err) + } + + return nil +} + +func resourceNetboxExtrasCustomFieldUpdate(ctx context.Context, d *schema.ResourceData, + m interface{}) diag.Diagnostics { + client := m.(*netboxclient.NetBoxAPI) + modifiedFields := make(map[string]interface{}) + + resourceID, err := strconv.ParseInt(d.Id(), 10, 64) + if err != nil { + return diag.Errorf("Unable to convert ID into int64") + } + params := &models.WritableCustomField{} + + if d.HasChange("choices") { + params.Choices = util.ToListofStrings(d.Get("choices").(*schema.Set).List()) + } + if d.HasChange("content_types") { + params.ContentTypes = util.ToListofStrings(d.Get("content_types").(*schema.Set).List()) + } + if d.HasChange("default") { + defaultvalue := d.Get("default").(string) + params.Default = &defaultvalue + modifiedFields["default"] = defaultvalue + } + if d.HasChange("description") { + params.Description = d.Get("description").(string) + modifiedFields["description"] = params.Description + } + if d.HasChange("filter_logic") { + params.FilterLogic = d.Get("filter_logic").(string) + } + if d.HasChange("label") { + params.Label = d.Get("label").(string) + modifiedFields["label"] = params.Label + } + if d.HasChange("name") { + name := d.Get("name").(string) + params.Name = &name + } + if d.HasChange("object_type") { + params.ObjectType = d.Get("object_type").(string) + } + if d.HasChange("required") { + params.Required = d.Get("required").(bool) + modifiedFields["required"] = params.Required + } + if d.HasChange("type") { + params.Type = d.Get("type").(string) + } + if d.HasChange("validation_maximum") { + validationMaximum := int64(d.Get("validation_maximum").(int)) + params.ValidationMaximum = &validationMaximum + if d.GetRawConfig().GetAttr("validation_maximum").IsNull() { + modifiedFields["validation_maximum"] = nil + } + } + if d.HasChange("validation_minimum") { + validationMinimum := int64(d.Get("validation_minimum").(int)) + params.ValidationMinimum = &validationMinimum + if d.GetRawConfig().GetAttr("validation_minimum").IsNull() { + modifiedFields["validation_minimum"] = nil + } + } + if d.HasChange("validation_regex") { + params.ValidationRegex = d.Get("validation_regex").(string) + modifiedFields["validation_regex"] = params.ValidationRegex + } + if d.HasChange("weight") { + weight := int64(d.Get("weight").(int)) + params.Weight = &weight + } + + resource := extras.NewExtrasCustomFieldsPartialUpdateParams().WithData(params) + + resource.SetID(resourceID) + + _, err = client.Extras.ExtrasCustomFieldsPartialUpdate(resource, nil, requestmodifier.NewNetboxRequestModifier(modifiedFields, customFieldRequiredFields)) + if err != nil { + return diag.FromErr(err) + } + + return resourceNetboxExtrasCustomFieldRead(ctx, d, m) +} + +func resourceNetboxExtrasCustomFieldDelete(ctx context.Context, d *schema.ResourceData, + m interface{}) diag.Diagnostics { + client := m.(*netboxclient.NetBoxAPI) + + resourceExists, err := resourceNetboxExtrasCustomFieldExists(d, m) + if err != nil { + return diag.FromErr(err) + } + + if !resourceExists { + return nil + } + + id, err := strconv.ParseInt(d.Id(), 10, 64) + if err != nil { + return diag.Errorf("Unable to convert ID into int64") + } + + resource := extras.NewExtrasCustomFieldsDeleteParams().WithID(id) + if _, err := client.Extras.ExtrasCustomFieldsDelete(resource, nil); err != nil { + return diag.FromErr(err) + } + + return nil +} + +func resourceNetboxExtrasCustomFieldExists(d *schema.ResourceData, + m interface{}) (b bool, e error) { + client := m.(*netboxclient.NetBoxAPI) + resourceExist := false + + resourceID := d.Id() + params := extras.NewExtrasCustomFieldsListParams().WithID(&resourceID) + resources, err := client.Extras.ExtrasCustomFieldsList(params, nil) + if err != nil { + return resourceExist, err + } + + for _, resource := range resources.Payload.Results { + if strconv.FormatInt(resource.ID, 10) == d.Id() { + resourceExist = true + } + } + + return resourceExist, nil +} diff --git a/netbox/extras/resource_netbox_extras_custom_field_boolean_test.go b/netbox/extras/resource_netbox_extras_custom_field_boolean_test.go new file mode 100644 index 000000000..aec613705 --- /dev/null +++ b/netbox/extras/resource_netbox_extras_custom_field_boolean_test.go @@ -0,0 +1,119 @@ +package extras_test + +import ( + "strconv" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/smutel/terraform-provider-netbox/v4/netbox/internal/util" +) + +const resourceNameNetboxExtrasCustomFieldBoolean = "netbox_extras_custom_field.test" + +func TestAccNetboxExtrasCustomFieldBooleanMinimal(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldBooleanConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldBoolean), + ), + }, + { + ResourceName: resourceNameNetboxExtrasCustomFieldBoolean, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccNetboxExtrasCustomFieldBooleanFull(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldBooleanConfig(nameSuffix, true, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldBoolean), + ), + }, + { + ResourceName: resourceNameNetboxExtrasCustomFieldBoolean, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccNetboxExtrasCustomFieldBooleanMinimalFullMinimal(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldBooleanConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldBoolean), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldBooleanConfig(nameSuffix, true, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldBoolean), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldBooleanConfig(nameSuffix, false, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldBoolean), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldBooleanConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldBoolean), + ), + }, + }, + }) +} + +func testAccCheckNetboxExtrasCustomFieldBooleanConfig(nameSuffix string, resourceFull, extraResources bool) string { + template := ` + resource "netbox_extras_custom_field" "test" { + name = "test_{{ .namesuffix }}" + content_types = [ + "dcim.site", + ] + + type = "boolean" + {{ if eq .resourcefull "true" }} + description = "Test custom field" + label = "Test Label for CF" + weight = 50 + #required = true + filter_logic = "disabled" + # Fixed in Netbox 3.3 + #default = true + {{ end }} + } + ` + data := map[string]string{ + "namesuffix": nameSuffix, + "resourcefull": strconv.FormatBool(resourceFull), + "extraresources": strconv.FormatBool(extraResources), + } + return util.RenderTemplate(template, data) +} diff --git a/netbox/extras/resource_netbox_extras_custom_field_date_test.go b/netbox/extras/resource_netbox_extras_custom_field_date_test.go new file mode 100644 index 000000000..4fbe78ddb --- /dev/null +++ b/netbox/extras/resource_netbox_extras_custom_field_date_test.go @@ -0,0 +1,119 @@ +package extras_test + +import ( + "strconv" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/smutel/terraform-provider-netbox/v4/netbox/internal/util" +) + +const resourceNameNetboxExtrasCustomFieldDate = "netbox_extras_custom_field.test" + +func TestAccNetboxExtrasCustomFieldDateMinimal(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldDateConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldDate), + ), + }, + { + ResourceName: resourceNameNetboxExtrasCustomFieldDate, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccNetboxExtrasCustomFieldDateFull(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldDateConfig(nameSuffix, true, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldDate), + ), + }, + { + ResourceName: resourceNameNetboxExtrasCustomFieldDate, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccNetboxExtrasCustomFieldDateMinimalFullMinimal(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldDateConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldDate), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldDateConfig(nameSuffix, true, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldDate), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldDateConfig(nameSuffix, false, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldDate), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldDateConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldDate), + ), + }, + }, + }) +} + +func testAccCheckNetboxExtrasCustomFieldDateConfig(nameSuffix string, resourceFull, extraResources bool) string { + template := ` + resource "netbox_extras_custom_field" "test" { + name = "test_{{ .namesuffix }}" + content_types = [ + "dcim.site", + ] + + type = "date" + {{ if eq .resourcefull "true" }} + description = "Test custom field" + label = "Test Label for CF" + weight = 50 + #required = true + filter_logic = "disabled" + # Fixed in Netbox 3.3 + #default = "2022-01-01" + {{ end }} + } + ` + data := map[string]string{ + "namesuffix": nameSuffix, + "resourcefull": strconv.FormatBool(resourceFull), + "extraresources": strconv.FormatBool(extraResources), + } + return util.RenderTemplate(template, data) +} diff --git a/netbox/extras/resource_netbox_extras_custom_field_integer_test.go b/netbox/extras/resource_netbox_extras_custom_field_integer_test.go new file mode 100644 index 000000000..52bcfebd8 --- /dev/null +++ b/netbox/extras/resource_netbox_extras_custom_field_integer_test.go @@ -0,0 +1,121 @@ +package extras_test + +import ( + "strconv" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/smutel/terraform-provider-netbox/v4/netbox/internal/util" +) + +const resourceNameNetboxExtrasCustomFieldInteger = "netbox_extras_custom_field.test" + +func TestAccNetboxExtrasCustomFieldIntegerMinimal(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldIntegerConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldInteger), + ), + }, + { + ResourceName: resourceNameNetboxExtrasCustomFieldInteger, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccNetboxExtrasCustomFieldIntegerFull(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldIntegerConfig(nameSuffix, true, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldInteger), + ), + }, + { + ResourceName: resourceNameNetboxExtrasCustomFieldInteger, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccNetboxExtrasCustomFieldIntegerMinimalFullMinimal(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldIntegerConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldInteger), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldIntegerConfig(nameSuffix, true, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldInteger), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldIntegerConfig(nameSuffix, false, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldInteger), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldIntegerConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldInteger), + ), + }, + }, + }) +} + +func testAccCheckNetboxExtrasCustomFieldIntegerConfig(nameSuffix string, resourceFull, extraResources bool) string { + template := ` + resource "netbox_extras_custom_field" "test" { + name = "test_{{ .namesuffix }}" + content_types = [ + "dcim.site", + ] + + type = "integer" + {{ if eq .resourcefull "true" }} + description = "Test custom field" + label = "Test Label for CF" + weight = 50 + #required = true + filter_logic = "disabled" + # Fixed in Netbox 3.3 + #default = 50 + validation_minimum = 1 + validation_maximum = 500 + {{ end }} + } + ` + data := map[string]string{ + "namesuffix": nameSuffix, + "resourcefull": strconv.FormatBool(resourceFull), + "extraresources": strconv.FormatBool(extraResources), + } + return util.RenderTemplate(template, data) +} diff --git a/netbox/extras/resource_netbox_extras_custom_field_json_test.go b/netbox/extras/resource_netbox_extras_custom_field_json_test.go new file mode 100644 index 000000000..768082744 --- /dev/null +++ b/netbox/extras/resource_netbox_extras_custom_field_json_test.go @@ -0,0 +1,125 @@ +package extras_test + +import ( + "strconv" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/smutel/terraform-provider-netbox/v4/netbox/internal/util" +) + +const resourceNameNetboxExtrasCustomFieldJSON = "netbox_extras_custom_field.test" + +func TestAccNetboxExtrasCustomFieldJSONMinimal(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldJSONConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldJSON), + ), + }, + { + ResourceName: resourceNameNetboxExtrasCustomFieldJSON, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccNetboxExtrasCustomFieldJSONFull(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldJSONConfig(nameSuffix, true, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldJSON), + ), + }, + { + ResourceName: resourceNameNetboxExtrasCustomFieldJSON, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccNetboxExtrasCustomFieldJSONMinimalFullMinimal(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldJSONConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldJSON), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldJSONConfig(nameSuffix, true, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldJSON), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldJSONConfig(nameSuffix, false, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldJSON), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldJSONConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldJSON), + ), + }, + }, + }) +} + +func testAccCheckNetboxExtrasCustomFieldJSONConfig(nameSuffix string, resourceFull, extraResources bool) string { + template := ` + resource "netbox_extras_custom_field" "test" { + name = "test_{{ .namesuffix }}" + content_types = [ + "dcim.site", + ] + + type = "json" + {{ if eq .resourcefull "true" }} + description = "Test custom field" + label = "Test Label for CF" + weight = 50 + #required = true + filter_logic = "disabled" + # Fixed in Netbox 3.3 + #default = jsonencode({ + # bool = false + # number = 1.5 + # dict = { + # text = "Some text"} + # } + #}) + {{ end }} + } + ` + data := map[string]string{ + "namesuffix": nameSuffix, + "resourcefull": strconv.FormatBool(resourceFull), + "extraresources": strconv.FormatBool(extraResources), + } + return util.RenderTemplate(template, data) +} diff --git a/netbox/extras/resource_netbox_extras_custom_field_longtext_test.go b/netbox/extras/resource_netbox_extras_custom_field_longtext_test.go new file mode 100644 index 000000000..1b2b0b5ad --- /dev/null +++ b/netbox/extras/resource_netbox_extras_custom_field_longtext_test.go @@ -0,0 +1,119 @@ +package extras_test + +import ( + "strconv" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/smutel/terraform-provider-netbox/v4/netbox/internal/util" +) + +const resourceNameNetboxExtrasCustomFieldLongtext = "netbox_extras_custom_field.test" + +func TestAccNetboxExtrasCustomFieldLongtextMinimal(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldLongtextConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldLongtext), + ), + }, + { + ResourceName: resourceNameNetboxExtrasCustomFieldLongtext, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccNetboxExtrasCustomFieldLongtextFull(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldLongtextConfig(nameSuffix, true, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldLongtext), + ), + }, + { + ResourceName: resourceNameNetboxExtrasCustomFieldLongtext, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccNetboxExtrasCustomFieldLongtextMinimalFullMinimal(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldLongtextConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldLongtext), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldLongtextConfig(nameSuffix, true, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldLongtext), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldLongtextConfig(nameSuffix, false, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldLongtext), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldLongtextConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldLongtext), + ), + }, + }, + }) +} + +func testAccCheckNetboxExtrasCustomFieldLongtextConfig(nameSuffix string, resourceFull, extraResources bool) string { + template := ` + resource "netbox_extras_custom_field" "test" { + name = "test_{{ .namesuffix }}" + content_types = [ + "dcim.site", + ] + + type = "longtext" + {{ if eq .resourcefull "true" }} + description = "Test custom field" + label = "Test Label for CF" + weight = 50 + #required = true + filter_logic = "disabled" + default = "Default text" + validation_regex = "^.*$" + {{ end }} + } + ` + data := map[string]string{ + "namesuffix": nameSuffix, + "resourcefull": strconv.FormatBool(resourceFull), + "extraresources": strconv.FormatBool(extraResources), + } + return util.RenderTemplate(template, data) +} diff --git a/netbox/extras/resource_netbox_extras_custom_field_multiobject_test.go b/netbox/extras/resource_netbox_extras_custom_field_multiobject_test.go new file mode 100644 index 000000000..f35018e87 --- /dev/null +++ b/netbox/extras/resource_netbox_extras_custom_field_multiobject_test.go @@ -0,0 +1,129 @@ +package extras_test + +import ( + "strconv" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/smutel/terraform-provider-netbox/v4/netbox/internal/util" +) + +const resourceNameNetboxExtrasCustomFieldMultiObject = "netbox_extras_custom_field.test" + +func TestAccNetboxExtrasCustomFieldMultiObjectMinimal(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldMultiObjectConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldMultiObject), + ), + }, + { + ResourceName: resourceNameNetboxExtrasCustomFieldMultiObject, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccNetboxExtrasCustomFieldMultiObjectFull(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldMultiObjectConfig(nameSuffix, true, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldMultiObject), + ), + }, + { + ResourceName: resourceNameNetboxExtrasCustomFieldMultiObject, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccNetboxExtrasCustomFieldMultiObjectMinimalFullMinimal(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldMultiObjectConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldMultiObject), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldMultiObjectConfig(nameSuffix, true, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldMultiObject), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldMultiObjectConfig(nameSuffix, false, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldMultiObject), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldMultiObjectConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldMultiObject), + ), + }, + }, + }) +} + +func testAccCheckNetboxExtrasCustomFieldMultiObjectConfig(nameSuffix string, resourceFull, extraResources bool) string { + template := ` + {{ if eq .extraresources "true" }} + resource "netbox_dcim_platform" "test" { + name = "test-{{ .namesuffix }}" + slug = "test-{{ .namesuffix }}" + } + {{ end }} + + resource "netbox_extras_custom_field" "test" { + name = "test_{{ .namesuffix }}" + content_types = [ + "dcim.site", + ] + + type = "multiobject" + object_type = "dcim.platform" + {{ if eq .resourcefull "true" }} + description = "Test custom field" + label = "Test Label for CF" + weight = 50 + #required = true + filter_logic = "disabled" + # Fixed in netbox 3.3 + #default = jsonencode([ + # netbox_dcim_platform.test.id + #]) + {{ end }} + } + ` + data := map[string]string{ + "namesuffix": nameSuffix, + "resourcefull": strconv.FormatBool(resourceFull), + "extraresources": strconv.FormatBool(extraResources), + } + return util.RenderTemplate(template, data) +} diff --git a/netbox/extras/resource_netbox_extras_custom_field_multiselect_test.go b/netbox/extras/resource_netbox_extras_custom_field_multiselect_test.go new file mode 100644 index 000000000..845fae422 --- /dev/null +++ b/netbox/extras/resource_netbox_extras_custom_field_multiselect_test.go @@ -0,0 +1,123 @@ +package extras_test + +import ( + "strconv" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/smutel/terraform-provider-netbox/v4/netbox/internal/util" +) + +const resourceNameNetboxExtrasCustomFieldMultiSelect = "netbox_extras_custom_field.test" + +func TestAccNetboxExtrasCustomFieldMultiSelectMinimal(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldMultiSelectConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldMultiSelect), + ), + }, + { + ResourceName: resourceNameNetboxExtrasCustomFieldMultiSelect, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccNetboxExtrasCustomFieldMultiSelectFull(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldMultiSelectConfig(nameSuffix, true, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldMultiSelect), + ), + }, + { + ResourceName: resourceNameNetboxExtrasCustomFieldMultiSelect, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccNetboxExtrasCustomFieldMultiSelectMinimalFullMinimal(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldMultiSelectConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldMultiSelect), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldMultiSelectConfig(nameSuffix, true, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldMultiSelect), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldMultiSelectConfig(nameSuffix, false, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldMultiSelect), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldMultiSelectConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldMultiSelect), + ), + }, + }, + }) +} + +func testAccCheckNetboxExtrasCustomFieldMultiSelectConfig(nameSuffix string, resourceFull, extraResources bool) string { + template := ` + resource "netbox_extras_custom_field" "test" { + name = "test_{{ .namesuffix }}" + content_types = [ + "dcim.site", + ] + + type = "multiselect" + {{ if eq .resourcefull "true" }} + description = "Test custom field" + choices = [ + "test", + "test2" + ] + label = "Test Label for CF" + weight = 50 + #required = true + filter_logic = "disabled" + # Fixed in netbox 3.3 + #default = "test" + {{ end }} + } + ` + data := map[string]string{ + "namesuffix": nameSuffix, + "resourcefull": strconv.FormatBool(resourceFull), + "extraresources": strconv.FormatBool(extraResources), + } + return util.RenderTemplate(template, data) +} diff --git a/netbox/extras/resource_netbox_extras_custom_field_object_test.go b/netbox/extras/resource_netbox_extras_custom_field_object_test.go new file mode 100644 index 000000000..b0e32f440 --- /dev/null +++ b/netbox/extras/resource_netbox_extras_custom_field_object_test.go @@ -0,0 +1,129 @@ +package extras_test + +import ( + "strconv" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/smutel/terraform-provider-netbox/v4/netbox/internal/util" +) + +const resourceNameNetboxExtrasCustomFieldObject = "netbox_extras_custom_field.test" + +func TestAccNetboxExtrasCustomFieldObjectMinimal(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldObjectConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldObject), + ), + }, + { + ResourceName: resourceNameNetboxExtrasCustomFieldObject, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccNetboxExtrasCustomFieldObjectFull(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldObjectConfig(nameSuffix, true, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldObject), + ), + }, + { + ResourceName: resourceNameNetboxExtrasCustomFieldObject, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccNetboxExtrasCustomFieldObjectMinimalFullMinimal(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldObjectConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldObject), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldObjectConfig(nameSuffix, true, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldObject), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldObjectConfig(nameSuffix, false, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldObject), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldObjectConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldObject), + ), + }, + }, + }) +} + +func testAccCheckNetboxExtrasCustomFieldObjectConfig(nameSuffix string, resourceFull, extraResources bool) string { + template := ` + {{ if eq .extraresources "true" }} + resource "netbox_dcim_platform" "test" { + name = "test-{{ .namesuffix }}" + slug = "test-{{ .namesuffix }}" + } + {{ end }} + + resource "netbox_extras_custom_field" "test" { + name = "test_{{ .namesuffix }}" + content_types = [ + "dcim.site", + ] + + type = "object" + object_type = "dcim.platform" + {{ if eq .resourcefull "true" }} + description = "Test custom field" + label = "Test Label for CF" + weight = 50 + #required = true + filter_logic = "disabled" + # Fixed in netbox 3.3 + #default = jsonencode([ + # netbox_dcim_platform.test.id + #]) + {{ end }} + } + ` + data := map[string]string{ + "namesuffix": nameSuffix, + "resourcefull": strconv.FormatBool(resourceFull), + "extraresources": strconv.FormatBool(extraResources), + } + return util.RenderTemplate(template, data) +} diff --git a/netbox/extras/resource_netbox_extras_custom_field_select_test.go b/netbox/extras/resource_netbox_extras_custom_field_select_test.go new file mode 100644 index 000000000..4ef9404e6 --- /dev/null +++ b/netbox/extras/resource_netbox_extras_custom_field_select_test.go @@ -0,0 +1,122 @@ +package extras_test + +import ( + "strconv" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/smutel/terraform-provider-netbox/v4/netbox/internal/util" +) + +const resourceNameNetboxExtrasCustomFieldSelect = "netbox_extras_custom_field.test" + +func TestAccNetboxExtrasCustomFieldSelectMinimal(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldSelectConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldSelect), + ), + }, + { + ResourceName: resourceNameNetboxExtrasCustomFieldSelect, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccNetboxExtrasCustomFieldSelectFull(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldSelectConfig(nameSuffix, true, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldSelect), + ), + }, + { + ResourceName: resourceNameNetboxExtrasCustomFieldSelect, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccNetboxExtrasCustomFieldSelectMinimalFullMinimal(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldSelectConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldSelect), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldSelectConfig(nameSuffix, true, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldSelect), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldSelectConfig(nameSuffix, false, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldSelect), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldSelectConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldSelect), + ), + }, + }, + }) +} + +func testAccCheckNetboxExtrasCustomFieldSelectConfig(nameSuffix string, resourceFull, extraResources bool) string { + template := ` + resource "netbox_extras_custom_field" "test" { + name = "test_{{ .namesuffix }}" + content_types = [ + "dcim.site", + ] + + type = "select" + {{ if eq .resourcefull "true" }} + description = "Test custom field" + choices = [ + "test", + "test2" + ] + label = "Test Label for CF" + weight = 50 + #required = true + filter_logic = "disabled" + default = "test" + {{ end }} + } + ` + data := map[string]string{ + "namesuffix": nameSuffix, + "resourcefull": strconv.FormatBool(resourceFull), + "extraresources": strconv.FormatBool(extraResources), + } + return util.RenderTemplate(template, data) +} diff --git a/netbox/extras/resource_netbox_extras_custom_field_text_test.go b/netbox/extras/resource_netbox_extras_custom_field_text_test.go new file mode 100644 index 000000000..47b5b62fa --- /dev/null +++ b/netbox/extras/resource_netbox_extras_custom_field_text_test.go @@ -0,0 +1,119 @@ +package extras_test + +import ( + "strconv" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/smutel/terraform-provider-netbox/v4/netbox/internal/util" +) + +const resourceNameNetboxExtrasCustomFieldText = "netbox_extras_custom_field.test" + +func TestAccNetboxExtrasCustomFieldTextMinimal(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldTextConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldText), + ), + }, + { + ResourceName: resourceNameNetboxExtrasCustomFieldText, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccNetboxExtrasCustomFieldTextFull(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldTextConfig(nameSuffix, true, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldText), + ), + }, + { + ResourceName: resourceNameNetboxExtrasCustomFieldText, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccNetboxExtrasCustomFieldTextMinimalFullMinimal(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldTextConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldText), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldTextConfig(nameSuffix, true, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldText), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldTextConfig(nameSuffix, false, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldText), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldTextConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldText), + ), + }, + }, + }) +} + +func testAccCheckNetboxExtrasCustomFieldTextConfig(nameSuffix string, resourceFull, extraResources bool) string { + template := ` + resource "netbox_extras_custom_field" "test" { + name = "test_{{ .namesuffix }}" + content_types = [ + "dcim.site", + ] + + type = "text" + {{ if eq .resourcefull "true" }} + description = "Test custom field" + label = "Test Label for CF" + weight = 50 + #required = true + filter_logic = "disabled" + default = "Default text" + validation_regex = "^.*$" + {{ end }} + } + ` + data := map[string]string{ + "namesuffix": nameSuffix, + "resourcefull": strconv.FormatBool(resourceFull), + "extraresources": strconv.FormatBool(extraResources), + } + return util.RenderTemplate(template, data) +} diff --git a/netbox/extras/resource_netbox_extras_custom_field_url_test.go b/netbox/extras/resource_netbox_extras_custom_field_url_test.go new file mode 100644 index 000000000..5479d2786 --- /dev/null +++ b/netbox/extras/resource_netbox_extras_custom_field_url_test.go @@ -0,0 +1,119 @@ +package extras_test + +import ( + "strconv" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/smutel/terraform-provider-netbox/v4/netbox/internal/util" +) + +const resourceNameNetboxExtrasCustomFieldURL = "netbox_extras_custom_field.test" + +func TestAccNetboxExtrasCustomFieldURLMinimal(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldURLConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldURL), + ), + }, + { + ResourceName: resourceNameNetboxExtrasCustomFieldURL, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccNetboxExtrasCustomFieldURLFull(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldURLConfig(nameSuffix, true, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldURL), + ), + }, + { + ResourceName: resourceNameNetboxExtrasCustomFieldURL, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccNetboxExtrasCustomFieldURLMinimalFullMinimal(t *testing.T) { + nameSuffix := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { util.TestAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckNetboxExtrasCustomFieldURLConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldURL), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldURLConfig(nameSuffix, true, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldURL), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldURLConfig(nameSuffix, false, true), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldURL), + ), + }, + { + Config: testAccCheckNetboxExtrasCustomFieldURLConfig(nameSuffix, false, false), + Check: resource.ComposeTestCheckFunc( + util.TestAccResourceExists(resourceNameNetboxExtrasCustomFieldURL), + ), + }, + }, + }) +} + +func testAccCheckNetboxExtrasCustomFieldURLConfig(nameSuffix string, resourceFull, extraResources bool) string { + template := ` + resource "netbox_extras_custom_field" "test" { + name = "test_{{ .namesuffix }}" + content_types = [ + "dcim.site", + ] + + type = "url" + {{ if eq .resourcefull "true" }} + description = "Test custom field" + label = "Test Label for CF" + weight = 50 + #required = true + filter_logic = "disabled" + # Fixed in Netbox 3.3 + #default = "https://netbox.dev/" + {{ end }} + } + ` + data := map[string]string{ + "namesuffix": nameSuffix, + "resourcefull": strconv.FormatBool(resourceFull), + "extraresources": strconv.FormatBool(extraResources), + } + return util.RenderTemplate(template, data) +} diff --git a/netbox/internal/util/util.go b/netbox/internal/util/util.go index 691002450..52a2f2038 100644 --- a/netbox/internal/util/util.go +++ b/netbox/internal/util/util.go @@ -76,6 +76,14 @@ func ToListofInts(in []interface{}) []int64 { return out } +func ToListofStrings(in []interface{}) []string { + out := make([]string, len(in)) + for i := range in { + out[i] = in[i].(string) + } + return out +} + func TrimString(val interface{}) string { return strings.TrimSpace(val.(string)) } diff --git a/netbox/provider.go b/netbox/provider.go index 87bdcceaf..ed49cf362 100644 --- a/netbox/provider.go +++ b/netbox/provider.go @@ -166,6 +166,7 @@ func Provider() *schema.Provider { "netbox_dcim_device_role": dcim.ResourceNetboxDcimDeviceRole(), "netbox_dcim_platform": dcim.ResourceNetboxDcimPlatform(), "netbox_dcim_site": dcim.ResourceNetboxDcimSite(), + "netbox_extras_custom_field": extras.ResourceNetboxExtrasCustomField(), "netbox_extras_tag": extras.ResourceNetboxExtrasTag(), "netbox_ipam_aggregate": ipam.ResourceNetboxIpamAggregate(), "netbox_ipam_asn": ipam.ResourceNetboxIpamASN(),