Skip to content

Commit

Permalink
feat: Add custom_fields to tenant resource
Browse files Browse the repository at this point in the history
  • Loading branch information
smutel committed Dec 12, 2020
1 parent a563b90 commit 01a000f
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 137 deletions.
16 changes: 16 additions & 0 deletions docs/resources/tenancy_tenant.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,29 @@ resource "netbox_tenancy_tenant" "tenant_test" {
name = "tag1"
slug = "tag1"
}
custom_fields = {
cf_boolean = "true"
cf_date = "2020-12-25"
cf_integer = "10"
cf_selection = "1"
cf_text = "Some text"
cf_url = "https://github.com"
}
}
```

## Argument Reference

The following arguments are supported:
* ``comments`` - (Optional) Comments for this object.
* ``custom_fields`` - (Optional) Custom Field Keys and Values for this object
** For boolean, use the string value "true" or "false"
** For data, use the string format "YYYY-MM-DD"
** For integer, use the value between double quote "10"
** For selection, use the level id
** For text, use the string value
** For URL, use the URL as string
* ``description`` - (Optional) The description for this object.
* ``tenant_group_id`` - (Optional) ID of the group where this object is located.
* ``name`` - (Required) The name for this object.
Expand Down
14 changes: 7 additions & 7 deletions docs/resources/virtualization_vm.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ resource "netbox_virtualization_vm" "vm_test" {
The following arguments are supported:
* ``cluster_id`` - (Required) ID of the cluster which host this object.
* ``comments`` - (Optional) Comments for this object.
* ``custom_fields`` - (Optional) Custom Field Keys and Values for this object
** For boolean, use the string value "true" or "false"
** For data, use the string format "YYYY-MM-DD"
** For integer, use the value between double quote "10"
** For selection, use the level id
** For text, use the string value
** For URL, use the URL as string
* ``disk`` - (Optional) The size in GB of the disk for this object.
* ``local_context_data`` - (Optional) Local context data for this object.
* ``memory`` - (Optional) The size in MB of the memory of this object.
Expand All @@ -45,13 +52,6 @@ The following arguments are supported:
The ``tag`` block supports:
* ``name`` - (Required) Name of the existing tag to associate with this resource.
* ``slug`` - (Required) Slug of the existing tag to associate with this resource.
* ``custom_fields`` - (Optional) Custom Field Keys and Values for this object
** For boolean, use the string value "true" or "false"
** For data, use the string format "YYYY-MM-DD"
** For integer, use the value between double quote "10"
** For selection, use the level id
** For text, use the string value
** For URL, use the URL as string

## Attributes Reference

Expand Down
18 changes: 18 additions & 0 deletions examples/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ resource "netbox_tenancy_tenant" "tenant_test" {
name = "tag2"
slug = "tag2"
}

custom_fields = {
cf_boolean = "true"
cf_date = "2020-12-25"
cf_integer = "10"
cf_selection = "1"
cf_text = "Some text"
cf_url = "https://github.com"
}
}

resource "netbox_tenancy_tenant_group" "tenant_group_test" {
Expand Down Expand Up @@ -116,6 +125,15 @@ resource "netbox_virtualization_vm" "vm_test" {
name = "tag1"
slug = "tag1"
}

custom_fields = {
cf_boolean = "true"
cf_date = "2020-12-25"
cf_integer = "10"
cf_selection = "1"
cf_text = "Some text"
cf_url = "https://github.com"
}
}

resource "netbox_virtualization_interface" "interface_test" {
Expand Down
43 changes: 38 additions & 5 deletions netbox/resource_netbox_tenancy_tenant.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,24 @@ func resourceNetboxTenancyTenant() *schema.Resource {
Optional: true,
Default: " ",
},
"custom_fields": {
Type: schema.TypeMap,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
// terraform default behavior sees a difference between null and an empty string
// therefore we override the default, because null in terraform results in empty string in netbox
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
// function is called for each member of map
// including additional call on the amount of entries
// we ignore the count, because the actual state always returns the amount of existing custom_fields and all are optional in terraform
if k == "custom_fields.%" {
return true
}
return old == new
},
},
"description": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -74,18 +92,21 @@ func resourceNetboxTenancyTenantCreate(d *schema.ResourceData,
client := m.(*netboxclient.NetBoxAPI)

comments := d.Get("comments").(string)
resourceCustomFields := d.Get("custom_fields").(map[string]interface{})
customFields := convertCustomFieldsFromTerraformToAPICreate(resourceCustomFields)
description := d.Get("description").(string)
groupID := int64(d.Get("tenant_group_id").(int))
name := d.Get("name").(string)
slug := d.Get("slug").(string)
tags := d.Get("tag").(*schema.Set).List()

newResource := &models.WritableTenant{
Comments: comments,
Description: description,
Name: &name,
Slug: &slug,
Tags: convertTagsToNestedTags(tags),
Comments: comments,
CustomFields: &customFields,
Description: description,
Name: &name,
Slug: &slug,
Tags: convertTagsToNestedTags(tags),
}

if groupID != 0 {
Expand Down Expand Up @@ -129,6 +150,12 @@ func resourceNetboxTenancyTenantRead(d *schema.ResourceData,
return err
}

customFields := convertCustomFieldsFromAPIToTerraform(resource.CustomFields)

if err = d.Set("custom_fields", customFields); err != nil {
return err
}

var description string

if resource.Description == "" {
Expand Down Expand Up @@ -188,6 +215,12 @@ func resourceNetboxTenancyTenantUpdate(d *schema.ResourceData,
params.Comments = comments
}

if d.HasChange("custom_fields") {
stateCustomFields, resourceCustomFields := d.GetChange("custom_fields")
customFields := convertCustomFieldsFromTerraformToAPIUpdate(stateCustomFields, resourceCustomFields)
params.CustomFields = &customFields
}

if d.HasChange("description") {
description := d.Get("description").(string)
params.Description = description
Expand Down
64 changes: 31 additions & 33 deletions netbox/resource_netbox_virtualization_vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,24 @@ func resourceNetboxVirtualizationVM() *schema.Resource {
Optional: true,
Default: " ",
},
"custom_fields": {
Type: schema.TypeMap,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
// terraform default behavior sees a difference between null and an empty string
// therefore we override the default, because null in terraform results in empty string in netbox
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
// function is called for each member of map
// including additional call on the amount of entries
// we ignore the count, because the actual state always returns the amount of existing custom_fields and all are optional in terraform
if k == "custom_fields.%" {
return true
}
return old == new
},
},
"disk": {
Type: schema.TypeInt,
Optional: true,
Expand Down Expand Up @@ -90,24 +108,6 @@ func resourceNetboxVirtualizationVM() *schema.Resource {
Optional: true,
Default: 0,
},
"custom_fields": {
Type: schema.TypeMap,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
// terraform default behavior sees a difference between null and an empty string
// therefore we override the default, because null in terraform results in empty string in netbox
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
// function is called for each member of map
// including additional call on the amount of entries
// we ignore the count, because the actual state always returns the amount of existing custom_fields and all are optional in terraform
if k == "custom_fields.%" {
return true
}
return old == new
},
},
},
}
}
Expand All @@ -134,6 +134,7 @@ func resourceNetboxVirtualizationVMCreate(d *schema.ResourceData,
newResource := &models.WritableVirtualMachineWithConfigContext{
Cluster: &clusterID,
Comments: comments,
CustomFields: &customFields,
LocalContextData: &localContextData,
Name: &name,
Status: status,
Expand Down Expand Up @@ -164,8 +165,6 @@ func resourceNetboxVirtualizationVMCreate(d *schema.ResourceData,
newResource.Vcpus = &vcpus
}

newResource.CustomFields = &customFields

resource := virtualization.NewVirtualizationVirtualMachinesCreateParams().WithData(newResource)

resourceCreated, err := client.Virtualization.VirtualizationVirtualMachinesCreate(resource, nil)
Expand Down Expand Up @@ -210,6 +209,12 @@ func resourceNetboxVirtualizationVMRead(d *schema.ResourceData,
return err
}

customFields := convertCustomFieldsFromAPIToTerraform(resource.CustomFields)

if err = d.Set("custom_fields", customFields); err != nil {
return err
}

if err = d.Set("disk", resource.Disk); err != nil {
return err
}
Expand Down Expand Up @@ -269,12 +274,6 @@ func resourceNetboxVirtualizationVMRead(d *schema.ResourceData,
return err
}

customFields := convertCustomFieldsFromAPIToTerraform(resource.CustomFields)

if err = d.Set("custom_fields", customFields); err != nil {
return err
}

return nil
}
}
Expand All @@ -299,6 +298,12 @@ func resourceNetboxVirtualizationVMUpdate(d *schema.ResourceData,
params.Comments = comments
}

if d.HasChange("custom_fields") {
stateCustomFields, resourceCustomFields := d.GetChange("custom_fields")
customFields := convertCustomFieldsFromTerraformToAPIUpdate(stateCustomFields, resourceCustomFields)
params.CustomFields = &customFields
}

if d.HasChange("disk") {
disk := int64(d.Get("disk").(int))
params.Disk = &disk
Expand Down Expand Up @@ -342,13 +347,6 @@ func resourceNetboxVirtualizationVMUpdate(d *schema.ResourceData,
params.Vcpus = &vcpus
}

//
if d.HasChange("custom_fields") {
stateCustomFields, resourceCustomFields := d.GetChange("custom_fields")
customFields := convertCustomFieldsFromTerraformToAPIUpdate(stateCustomFields, resourceCustomFields)
params.CustomFields = &customFields
}

resource := virtualization.NewVirtualizationVirtualMachinesPartialUpdateParams().WithData(params)

resourceID, err := strconv.ParseInt(d.Id(), 10, 64)
Expand Down
92 changes: 0 additions & 92 deletions netbox/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,98 +139,6 @@ func updatePrimaryStatus(m interface{}, info InfosForPrimary, id int64) error {
return nil
}

/*
* func diffSlices(oldSlice []string, newSlice []string) []string {
* var diff []string
*
* for _, x := range oldSlice {
* found := false
* for _, y := range newSlice {
* if x == y {
* found = true
* }
* }
*
* if found == false {
* diff = append(diff, x)
* }
* }
*
* return diff
* }
*/

/*
* func convertCFToAPI(customFields []interface{}) (cf map[string]interface{},
* e error) {
*
* customFieldsAPI := make(map[string]interface{})
* for _, customFieldRaw := range customFields {
* customField := customFieldRaw.(map[string]interface{})
* customFieldName := customField["name"].(string)
* customFieldType := customField["kind"].(string)
* customFieldValue := customField["value"].(string)
*
* if customFieldType == "string" {
* customFieldsAPI[customFieldName] = customFieldValue
* } else if customFieldType == "int" {
* cfIntValue, err := strconv.ParseInt(customFieldValue, 10, 64)
* if err != nil {
* return nil, err
* }
* customFieldsAPI[customFieldName] = cfIntValue
* } else if customFieldType == "bool" {
* cfBoolValue, err := strconv.ParseBool(customFieldValue)
* if err != nil {
* return nil, err
* }
* customFieldsAPI[customFieldName] = cfBoolValue
* }
* }
*
* return customFieldsAPI, nil
* }
*/

/*
* func convertAPIToCF(customFields interface{}) (cf []map[string]string) {
* var cfAPI map[string]string
* cfAPISize := 0
*
* for _, v := range customFields.(map[string]interface{}) {
* if v != nil {
* cfAPISize++
* }
* }
*
* customFieldsAPI := make([]map[string]string, cfAPISize)
*
* i := 0
* for k, v := range customFields.(map[string]interface{}) {
* cfAPI = make(map[string]string)
* cfAPI["name"] = k
*
* if v != nil {
* switch v.(type) {
* case json.Number:
* cfAPI["value"] = v.(json.Number).String()
* cfAPI["kind"] = "int"
* case bool:
* cfAPI["value"] = strconv.FormatBool(v.(bool))
* cfAPI["kind"] = "bool"
* default:
* cfAPI["value"] = v.(string)
* cfAPI["kind"] = "string"
* }
* customFieldsAPI[i] = cfAPI
* i++
* }
* }
*
* return customFieldsAPI
* }
*/

// custom_fields have multiple data type returns based on field type
// but terraform only supports map[string]string, so we convert all to strings
func convertCustomFieldsFromAPIToTerraform(customFields interface{}) map[string]string {
Expand Down

0 comments on commit 01a000f

Please sign in to comment.