diff --git a/go.mod b/go.mod index d7065a9..cf36116 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.19 require ( github.com/coreos/go-semver v0.3.0 + github.com/disaster37/es-handler/v8 v8.0.2 github.com/disaster37/go-kibana-rest/v8 v8.5.0 github.com/elastic/go-ucfg v0.8.6 github.com/hashicorp/terraform-plugin-sdk/v2 v2.24.0 @@ -16,6 +17,8 @@ require ( github.com/agext/levenshtein v1.2.2 // indirect github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/elastic/elastic-transport-go/v8 v8.1.0 // indirect + github.com/elastic/go-elasticsearch/v8 v8.4.0 // indirect github.com/fatih/color v1.13.0 // indirect github.com/go-resty/resty/v2 v2.7.0 // indirect github.com/golang/protobuf v1.5.2 // indirect @@ -39,6 +42,8 @@ require ( github.com/hashicorp/terraform-registry-address v0.0.0-20220623143253-7d51757b572c // indirect github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 // indirect github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect @@ -47,6 +52,7 @@ require ( github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/oklog/run v1.0.0 // indirect + github.com/olivere/elastic/v7 v7.0.32 // indirect github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect github.com/vmihailenco/msgpack/v4 v4.3.12 // indirect github.com/vmihailenco/tagparser v0.1.1 // indirect diff --git a/go.sum b/go.sum index 8c37759..e45315f 100644 --- a/go.sum +++ b/go.sum @@ -33,8 +33,14 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/disaster37/es-handler/v8 v8.0.2 h1:pBYMYSsOT8LNKW2mKGjjk7ZVB247l3y8MYPyMrfNFqc= +github.com/disaster37/es-handler/v8 v8.0.2/go.mod h1:kl0VY2rLO5CX1KkVib088A2NIFexWJTZ2bqzlgYJka8= github.com/disaster37/go-kibana-rest/v8 v8.5.0 h1:Wr2CMopHj0wAh7kq3p355jXctISL1LdAZ9kYN/v6abw= github.com/disaster37/go-kibana-rest/v8 v8.5.0/go.mod h1:wVGm1b93CSmsHYoxzqhDszv347xr+fELdigS8XLO+bg= +github.com/elastic/elastic-transport-go/v8 v8.1.0 h1:NeqEz1ty4RQz+TVbUrpSU7pZ48XkzGWQj02k5koahIE= +github.com/elastic/elastic-transport-go/v8 v8.1.0/go.mod h1:87Tcz8IVNe6rVSLdBux1o/PEItLtyabHU3naC7IoqKI= +github.com/elastic/go-elasticsearch/v8 v8.4.0 h1:Rn1mcqaIMcNT43hnx2H62cIFZ+B6mjWtzj85BDKrvCE= +github.com/elastic/go-elasticsearch/v8 v8.4.0/go.mod h1:yY52i2Vj0unLz+N3Nwx1gM5LXwoj3h2dgptNGBYkMLA= github.com/elastic/go-ucfg v0.8.6 h1:stUeyh2goTgGX+/wb9gzKvTv0YB0231LTpKUgCKj4U0= github.com/elastic/go-ucfg v0.8.6/go.mod h1:4E8mPOLSUV9hQ7sgLEJ4bvt0KhMuDJa8joDT2QGAEKA= github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= @@ -48,6 +54,7 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= @@ -139,10 +146,13 @@ github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1 github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/jarcoal/httpmock v1.2.0 h1:gSvTxxFR/MEMfsGrvRbdfpRUMBStovlSRLw0Ep1bwwc= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck= github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -155,6 +165,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= @@ -179,6 +191,8 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce h1:RPclfga2SEJmgMmz2k+Mg7cowZ8yv4Trqw9UsJby758= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/olivere/elastic/v7 v7.0.32 h1:R7CXvbu8Eq+WlsLgxmKVKPox0oOwAE/2T9Si5BnvK6E= +github.com/olivere/elastic/v7 v7.0.32/go.mod h1:c7PVmLe3Fxq77PIfY/bZmxY/TAamBhCzZ8xDOE09a9k= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/kb/diff_suppress_funcs.go b/kb/diff_suppress_funcs.go index c2fcb4d..0d7fed5 100644 --- a/kb/diff_suppress_funcs.go +++ b/kb/diff_suppress_funcs.go @@ -1,42 +1,79 @@ package kb import ( + "encoding/json" "fmt" "strings" - "github.com/elastic/go-ucfg" - "github.com/elastic/go-ucfg/diff" - ucfgjson "github.com/elastic/go-ucfg/json" + eshandler "github.com/disaster37/es-handler/v8" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" log "github.com/sirupsen/logrus" ) -// suppressEquivalentJSON permit to compare json string +// suppressEquivalentJSON permit to compare state store as JSON string func suppressEquivalentJSON(k, old, new string, d *schema.ResourceData) bool { + + var err error + oldObj := map[string]any{} + newObj := map[string]any{} + if old == "" { - old = `{}` + old = "{}" } if new == "" { - new = `{}` + new = "{}" } - confOld, err := ucfgjson.NewConfig([]byte(old), ucfg.PathSep(".")) - if err != nil { + + if err = json.Unmarshal([]byte(old), &oldObj); err != nil { fmt.Printf("[ERR] Error when converting current Json: %s\ndata: %s", err.Error(), old) log.Errorf("Error when converting current Json: %s\ndata: %s", err.Error(), old) - return false } - confNew, err := ucfgjson.NewConfig([]byte(new), ucfg.PathSep(".")) + if err = json.Unmarshal([]byte(new), &newObj); err != nil { + fmt.Printf("[ERR] Error when converting current Json: %s\ndata: %s", err.Error(), new) + log.Errorf("Error when converting current Json: %s\ndata: %s", err.Error(), new) + } + + diff, err := eshandler.StandardDiff(oldObj, newObj, logEntry, nil) if err != nil { - fmt.Printf("[ERR] Error when converting new Json: %s\ndata: %s", err.Error(), new) - log.Errorf("Error when converting new Json: %s\ndata: %s", err.Error(), new) + fmt.Printf("[ERR] Error when diff JSON: %s", err.Error()) + log.Errorf("Error when diff Json: %s", err.Error()) return false } - currentDiff := diff.CompareConfigs(confOld, confNew) - log.Debugf("Diff\n: %s", currentDiff.GoStringer()) + return diff == "" +} + +func suppressEquivalentJSONWithExclude(k, old, new string, d *schema.ResourceData, exclude map[string]any) bool { + + var err error + oldObj := map[string]any{} + newObj := map[string]any{} + + if old == "" { + old = "{}" + } + if new == "" { + new = "{}" + } + + if err = json.Unmarshal([]byte(old), &oldObj); err != nil { + fmt.Printf("[ERR] Error when converting current Json: %s\ndata: %s", err.Error(), old) + log.Errorf("Error when converting current Json: %s\ndata: %s", err.Error(), old) + } + if err = json.Unmarshal([]byte(new), &newObj); err != nil { + fmt.Printf("[ERR] Error when converting current Json: %s\ndata: %s", err.Error(), new) + log.Errorf("Error when converting current Json: %s\ndata: %s", err.Error(), new) + } - return !currentDiff.HasChanged() + diff, err := eshandler.StandardDiff(oldObj, newObj, logEntry, exclude) + if err != nil { + fmt.Printf("[ERR] Error when diff JSON: %s", err.Error()) + log.Errorf("Error when diff Json: %s", err.Error()) + return false + } + + return diff == "" } // Split NDJson by keeping only not emty lines @@ -56,79 +93,65 @@ func splitNDJSON(val string) []string { // suppressEquivalentNDJSON permit to compare ndjson string func suppressEquivalentNDJSON(k, old, new string, d *schema.ResourceData) bool { + var err error + excludeFields := map[string]any{ + "version": nil, + "updated_at": nil, + "coreMigrationVersion": nil, + "migrationVersion": nil, + "references": nil, + "sort": nil, + } + // NDJSON mean sthat each line correspond to JSON struct oldSlice := splitNDJSON(old) newSlice := splitNDJSON(new) - oldObjSlice := make([]*ucfg.Config, len(oldSlice)) - newObjSlice := make([]*ucfg.Config, len(newSlice)) + oldObjSlice := make([]map[string]any, len(oldSlice)) + newObjSlice := make([]map[string]any, len(newSlice)) if len(oldSlice) != len(newSlice) { return false } - // Convert string line to JSON + // Convert each line to map of string to compare the same object id for i, oldJSON := range oldSlice { - if oldJSON == "" { - oldJSON = `{}` - } - config, err := ucfgjson.NewConfig([]byte(oldJSON), ucfg.PathSep(".")) - if err != nil { - fmt.Printf("[ERR] Error when converting current Json: %s\ndata: %s", err.Error(), oldJSON) - log.Errorf("Error when converting current Json: %s\ndata: %s", err.Error(), oldJSON) - return false + res := map[string]any{} + if oldJSON != "" { + if err = json.Unmarshal([]byte(oldJSON), &res); err != nil { + fmt.Printf("[ERR] Error when unmarshal old Json: %s\ndata: %s", err.Error(), oldJSON) + log.Errorf("Error when unmarshal old Json: %s\ndata: %s", err.Error(), oldJSON) + return false + } } - //nolint:errcheck - config.Remove("version", -1) - //nolint:errcheck - config.Remove("updated_at", -1) - - oldObjSlice[i] = config + oldObjSlice[i] = res } + for i, newJSON := range newSlice { - if newJSON == "" { - newJSON = `{}` - } - config, err := ucfgjson.NewConfig([]byte(newJSON), ucfg.PathSep(".")) - if err != nil { - fmt.Printf("[ERR] Error when converting new Json: %s\ndata: %s", err.Error(), newJSON) - log.Errorf("Error when converting new Json: %s\ndata: %s", err.Error(), newJSON) - return false - } - //nolint:errcheck - config.Remove("version", -1) - //nolint:errcheck - config.Remove("updated_at", -1) + res := map[string]any{} + if newJSON != "" { + if err = json.Unmarshal([]byte(newJSON), &res); err != nil { + fmt.Printf("[ERR] Error when unmarshal nes Json: %s\ndata: %s", err.Error(), newJSON) + log.Errorf("Error when unmarshal new Json: %s\ndata: %s", err.Error(), newJSON) + return false - newObjSlice[i] = config + } + } + newObjSlice[i] = res } // Compare json obj - for i, oldConfig := range oldObjSlice { + for i, oldItem := range oldObjSlice { isFound := false - if !oldConfig.HasField("id") { + if oldItem["id"] == "" { return false } - oldId, err := oldConfig.String("id", -1) - if err != nil { - log.Errorf("Error when get ID on current Json: %s\ndata: %s", err.Error(), oldSlice[i]) - fmt.Printf("[ERR] Error when get ID on current Json: %s\ndata: %s", err.Error(), oldSlice[i]) - return false - } - for j, newConfig := range newObjSlice { - if !newConfig.HasField("id") { + for j, newItem := range newObjSlice { + if newItem["id"] == "" { return false } - newId, err := newConfig.String("id", -1) - if err != nil { - log.Errorf("Error when get ID on new Json: %s\ndata: %s", err.Error(), newSlice[j]) - fmt.Printf("[ERR] Error when get ID on new Json: %s\ndata: %s", err.Error(), newSlice[j]) - return false - } - - if oldId == newId { - currentDiff := diff.CompareConfigs(oldConfig, newConfig) - log.Debugf("Diff\n: %s", currentDiff.GoStringer()) - if currentDiff.HasChanged() { + // Compare same items + if oldItem["id"] == newItem["id"] { + if !suppressEquivalentJSONWithExclude(k, oldSlice[i], newSlice[j], d, excludeFields) { return false } isFound = true diff --git a/kb/provider.go b/kb/provider.go index e3a1e6f..511ef0e 100644 --- a/kb/provider.go +++ b/kb/provider.go @@ -11,9 +11,12 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/pkg/errors" + "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus" ) +var logEntry *logrus.Entry + // Provider define kibana provider func Provider() *schema.Provider { return &schema.Provider{ @@ -62,6 +65,12 @@ func Provider() *schema.Provider { Default: 10, Description: "Wait time in second before retry connexion", }, + "debug": { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Set logger to debug on Elasticsearch client", + }, }, ResourcesMap: map[string]*schema.Resource{ @@ -89,6 +98,7 @@ func providerConfigure(ctx context.Context, d *schema.ResourceData) (interface{} password := d.Get("password").(string) retry := d.Get("retry").(int) waitBeforeRetry := d.Get("wait_before_retry").(int) + debug := d.Get("debug").(bool) // Checks is valid URL if _, err := url.Parse(URL); err != nil { @@ -113,6 +123,12 @@ func providerConfigure(ctx context.Context, d *schema.ResourceData) (interface{} return nil, diag.FromErr(err) } + logger := log.New() + if debug { + logger.SetLevel(log.DebugLevel) + } + logEntry = log.NewEntry(logger) + // Test connexion and check kibana version nbFailed := 0 isOnline := false diff --git a/tests/kibana_object/terraform.tf b/tests/kibana_object/terraform.tf index c901cb6..a8a59bb 100644 --- a/tests/kibana_object/terraform.tf +++ b/tests/kibana_object/terraform.tf @@ -17,5 +17,8 @@ resource "kibana_object" "test" { name = "terraform-test" data = "{\"id\": \"test\", \"type\": \"index-pattern\",\"attributes\": {\"title\": \"test\"}}" deep_reference = "true" - export_types = ["index-pattern"] + export_objects { + id = "test" + type = "index-pattern" + } } \ No newline at end of file