Skip to content

Commit b1d3ca7

Browse files
committed
Fix state drift in netbox_prefix custom fields by normalizing values, handling object references, and suppressing nil/empty diffs.
Signed-off-by: Lorenzo Buitizon <the.keikun@gmail.com>
1 parent 74fb89e commit b1d3ca7

File tree

2 files changed

+48
-2
lines changed

2 files changed

+48
-2
lines changed

netbox/client.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
package netbox
22

33
import (
4+
"encoding/json"
45
"fmt"
6+
"io"
57
"net/http"
68
"time"
79

810
netboxclient "github.com/fbreckle/go-netbox/netbox/client"
11+
"github.com/go-openapi/runtime"
912
httptransport "github.com/go-openapi/runtime/client"
1013
"github.com/goware/urlx"
1114
log "github.com/sirupsen/logrus"
@@ -83,6 +86,16 @@ func (cfg *Config) Client() (*netboxclient.NetBoxAPI, error) {
8386
transport := httptransport.NewWithClient(parsedURL.Host, parsedURL.Path+netboxclient.DefaultBasePath, desiredRuntimeClientSchemes, httpClient)
8487
transport.DefaultAuthentication = httptransport.APIKeyAuth("Authorization", "header", fmt.Sprintf("Token %v", cfg.APIToken))
8588
transport.SetLogger(log.StandardLogger())
89+
90+
// Configure the transport to handle interface{} values properly
91+
// This helps prevent TextConsumer issues with interface{} types
92+
transport.Consumers["application/json"] = runtime.ConsumerFunc(func(reader io.Reader, data interface{}) error {
93+
dec := json.NewDecoder(reader)
94+
// Use json.Number to handle numeric values that might be interface{}
95+
dec.UseNumber()
96+
return dec.Decode(data)
97+
})
98+
8699
netboxClient := netboxclient.New(transport, nil)
87100

88101
return netboxClient, nil

netbox/custom_fields.go

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,47 @@ var customFieldsSchema = &schema.Schema{
2020
Type: schema.TypeString,
2121
Default: nil,
2222
},
23+
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
24+
if old == "" && new == "0" {
25+
return true // treat empty and "0" as equal? Wait, for maps it's different
26+
}
27+
// For maps, old and new are JSON strings
28+
if old == "{}" && new == "" {
29+
return true
30+
}
31+
if old == "" && new == "{}" {
32+
return true
33+
}
34+
return false
35+
},
2336
}
2437

2538
func getCustomFields(cf interface{}) map[string]interface{} {
2639
cfm, ok := cf.(map[string]interface{})
27-
if !ok || len(cfm) == 0 {
40+
if !ok {
2841
return nil
2942
}
30-
return cfm
43+
if len(cfm) == 0 {
44+
return map[string]interface{}{}
45+
}
46+
result := make(map[string]interface{})
47+
for k, v := range cfm {
48+
if v != nil {
49+
if m, ok := v.(map[string]interface{}); ok {
50+
// Handle object references by extracting ID
51+
if id, ok := m["id"]; ok {
52+
result[k] = fmt.Sprintf("%v", id)
53+
} else {
54+
result[k] = fmt.Sprintf("%v", v)
55+
}
56+
} else {
57+
result[k] = fmt.Sprintf("%v", v)
58+
}
59+
} else {
60+
result[k] = ""
61+
}
62+
}
63+
return result
3164
}
3265

3366
// flattenCustomFields converts custom fields to a map where all values are strings.

0 commit comments

Comments
 (0)