diff --git a/changelog/fragments/1668434027-Accept-raw-errors-as-a-fallback-to-detailed-error-type.yaml b/changelog/fragments/1668434027-Accept-raw-errors-as-a-fallback-to-detailed-error-type.yaml new file mode 100644 index 0000000000..161880626d --- /dev/null +++ b/changelog/fragments/1668434027-Accept-raw-errors-as-a-fallback-to-detailed-error-type.yaml @@ -0,0 +1,31 @@ +# Kind can be one of: +# - breaking-change: a change to previously-documented behavior +# - deprecation: functionality that is being removed in a later release +# - bug-fix: fixes a problem in a previous version +# - enhancement: extends functionality but does not break or fix existing behavior +# - feature: new functionality +# - known-issue: problems that we are aware of in a given version +# - security: impacts on the security of a product or a user’s deployment. +# - upgrade: important information for someone upgrading from a prior version +# - other: does not fit into any of the other categories +kind: feature + +# Change summary; a 80ish characters long description of the change. +summary: Accept raw errors as a fallback to detailed error type + +# Long description; in case the summary is not enough to describe the change +# this field accommodate a description without length limits. +#description: + +# Affected component; a word indicating the component this changeset affects. +component: + +# PR number; optional; the PR number that added the changeset. +# If not present is automatically filled by the tooling finding the PR where this changelog fragment has been added. +# NOTE: the tooling supports backports, so it's able to fill the original PR number instead of the backport PR number. +# Please provide it if you are adding a fragment for a different PR. +pr: 2079 + +# Issue number; optional; the GitHub issue related to this changeset (either closes or is part of). +# If not present is automatically filled by the tooling with the issue linked to the PR number. +issue: https://github.com/elastic/elastic-agent/issues/931 diff --git a/internal/pkg/bulk/helpers.go b/internal/pkg/bulk/helpers.go index d4ad7ef359..926b6d0953 100644 --- a/internal/pkg/bulk/helpers.go +++ b/internal/pkg/bulk/helpers.go @@ -30,7 +30,7 @@ func (u UpdateFields) Marshal() ([]byte, error) { func parseError(res *esapi.Response) error { var e struct { - Err *es.ErrorT `json:"error"` + Err json.RawMessage `json:"error"` } decoder := json.NewDecoder(res.Body) diff --git a/internal/pkg/bulk/schema.go b/internal/pkg/bulk/schema.go index f20833c4de..06ec1038a8 100644 --- a/internal/pkg/bulk/schema.go +++ b/internal/pkg/bulk/schema.go @@ -58,7 +58,7 @@ type BulkIndexerResponseItem struct { // Failed int `json:"failed"` // } `json:"_shards"` - Error *es.ErrorT `json:"error,omitempty"` + Error json.RawMessage `json:"error,omitempty"` } func (b *BulkIndexerResponseItem) deriveError() error { @@ -110,7 +110,7 @@ type MsearchResponseItem struct { Hits es.HitsT `json:"hits"` Aggregations map[string]es.Aggregation `json:"aggregations,omitempty"` - Error *es.ErrorT `json:"error,omitempty"` + Error json.RawMessage `json:"error,omitempty"` } //easyjson:json diff --git a/internal/pkg/bulk/schema_easyjson.go b/internal/pkg/bulk/schema_easyjson.go index ff9720747b..345d09643d 100644 --- a/internal/pkg/bulk/schema_easyjson.go +++ b/internal/pkg/bulk/schema_easyjson.go @@ -22,117 +22,7 @@ var ( _ easyjson.Marshaler ) -func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk(in *jlexer.Lexer, out *bulkIndexerResponse) { - isTopLevel := in.IsStart() - if in.IsNull() { - if isTopLevel { - in.Consumed() - } - in.Skip() - return - } - in.Delim('{') - for !in.IsDelim('}') { - key := in.UnsafeFieldName(false) - in.WantColon() - if in.IsNull() { - in.Skip() - in.WantComma() - continue - } - switch key { - case "took": - out.Took = int(in.Int()) - case "errors": - out.HasErrors = bool(in.Bool()) - case "items": - if in.IsNull() { - in.Skip() - out.Items = nil - } else { - in.Delim('[') - if out.Items == nil { - if !in.IsDelim(']') { - out.Items = make([]bulkStubItem, 0, 2) - } else { - out.Items = []bulkStubItem{} - } - } else { - out.Items = (out.Items)[:0] - } - for !in.IsDelim(']') { - var v1 bulkStubItem - easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk1(in, &v1) - out.Items = append(out.Items, v1) - in.WantComma() - } - in.Delim(']') - } - default: - in.SkipRecursive() - } - in.WantComma() - } - in.Delim('}') - if isTopLevel { - in.Consumed() - } -} -func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk(out *jwriter.Writer, in bulkIndexerResponse) { - out.RawByte('{') - first := true - _ = first - { - const prefix string = ",\"took\":" - out.RawString(prefix[1:]) - out.Int(int(in.Took)) - } - { - const prefix string = ",\"errors\":" - out.RawString(prefix) - out.Bool(bool(in.HasErrors)) - } - if len(in.Items) != 0 { - const prefix string = ",\"items\":" - out.RawString(prefix) - { - out.RawByte('[') - for v2, v3 := range in.Items { - if v2 > 0 { - out.RawByte(',') - } - easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk1(out, v3) - } - out.RawByte(']') - } - } - out.RawByte('}') -} - -// MarshalJSON supports json.Marshaler interface -func (v bulkIndexerResponse) MarshalJSON() ([]byte, error) { - w := jwriter.Writer{} - easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk(&w, v) - return w.Buffer.BuildBytes(), w.Error -} - -// MarshalEasyJSON supports easyjson.Marshaler interface -func (v bulkIndexerResponse) MarshalEasyJSON(w *jwriter.Writer) { - easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk(w, v) -} - -// UnmarshalJSON supports json.Unmarshaler interface -func (v *bulkIndexerResponse) UnmarshalJSON(data []byte) error { - r := jlexer.Lexer{Data: data} - easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk(&r, v) - return r.Error() -} - -// UnmarshalEasyJSON supports easyjson.Unmarshaler interface -func (v *bulkIndexerResponse) UnmarshalEasyJSON(l *jlexer.Lexer) { - easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk(l, v) -} -func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk1(in *jlexer.Lexer, out *bulkStubItem) { +func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk(in *jlexer.Lexer, out *bulkStubItem) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -159,7 +49,7 @@ func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk1(in *jle if out.Index == nil { out.Index = new(BulkIndexerResponseItem) } - easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk2(in, out.Index) + (*out.Index).UnmarshalEasyJSON(in) } case "delete": if in.IsNull() { @@ -169,7 +59,7 @@ func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk1(in *jle if out.Delete == nil { out.Delete = new(BulkIndexerResponseItem) } - easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk2(in, out.Delete) + (*out.Delete).UnmarshalEasyJSON(in) } case "create": if in.IsNull() { @@ -179,7 +69,7 @@ func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk1(in *jle if out.Create == nil { out.Create = new(BulkIndexerResponseItem) } - easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk2(in, out.Create) + (*out.Create).UnmarshalEasyJSON(in) } case "update": if in.IsNull() { @@ -189,7 +79,7 @@ func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk1(in *jle if out.Update == nil { out.Update = new(BulkIndexerResponseItem) } - easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk2(in, out.Update) + (*out.Update).UnmarshalEasyJSON(in) } default: in.SkipRecursive() @@ -201,7 +91,7 @@ func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk1(in *jle in.Consumed() } } -func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk1(out *jwriter.Writer, in bulkStubItem) { +func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk(out *jwriter.Writer, in bulkStubItem) { out.RawByte('{') first := true _ = first @@ -211,7 +101,7 @@ func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk1(out *jw if in.Index == nil { out.RawString("null") } else { - easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk2(out, *in.Index) + (*in.Index).MarshalEasyJSON(out) } } { @@ -220,7 +110,7 @@ func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk1(out *jw if in.Delete == nil { out.RawString("null") } else { - easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk2(out, *in.Delete) + (*in.Delete).MarshalEasyJSON(out) } } { @@ -229,7 +119,7 @@ func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk1(out *jw if in.Create == nil { out.RawString("null") } else { - easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk2(out, *in.Create) + (*in.Create).MarshalEasyJSON(out) } } { @@ -238,187 +128,36 @@ func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk1(out *jw if in.Update == nil { out.RawString("null") } else { - easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk2(out, *in.Update) + (*in.Update).MarshalEasyJSON(out) } } out.RawByte('}') } -func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk2(in *jlexer.Lexer, out *BulkIndexerResponseItem) { - isTopLevel := in.IsStart() - if in.IsNull() { - if isTopLevel { - in.Consumed() - } - in.Skip() - return - } - in.Delim('{') - for !in.IsDelim('}') { - key := in.UnsafeFieldName(false) - in.WantColon() - if in.IsNull() { - in.Skip() - in.WantComma() - continue - } - switch key { - case "_id": - out.DocumentID = string(in.String()) - case "status": - out.Status = int(in.Int()) - case "error": - if in.IsNull() { - in.Skip() - out.Error = nil - } else { - if out.Error == nil { - out.Error = new(es.ErrorT) - } - easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgEs(in, out.Error) - } - default: - in.SkipRecursive() - } - in.WantComma() - } - in.Delim('}') - if isTopLevel { - in.Consumed() - } -} -func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk2(out *jwriter.Writer, in BulkIndexerResponseItem) { - out.RawByte('{') - first := true - _ = first - { - const prefix string = ",\"_id\":" - out.RawString(prefix[1:]) - out.String(string(in.DocumentID)) - } - { - const prefix string = ",\"status\":" - out.RawString(prefix) - out.Int(int(in.Status)) - } - if in.Error != nil { - const prefix string = ",\"error\":" - out.RawString(prefix) - easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgEs(out, *in.Error) - } - out.RawByte('}') -} -func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgEs(in *jlexer.Lexer, out *es.ErrorT) { - isTopLevel := in.IsStart() - if in.IsNull() { - if isTopLevel { - in.Consumed() - } - in.Skip() - return - } - in.Delim('{') - for !in.IsDelim('}') { - key := in.UnsafeFieldName(false) - in.WantColon() - if in.IsNull() { - in.Skip() - in.WantComma() - continue - } - switch key { - case "type": - out.Type = string(in.String()) - case "reason": - out.Reason = string(in.String()) - case "caused_by": - easyjsonCef4e921Decode(in, &out.Cause) - default: - in.SkipRecursive() - } - in.WantComma() - } - in.Delim('}') - if isTopLevel { - in.Consumed() - } + +// MarshalJSON supports json.Marshaler interface +func (v bulkStubItem) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk(&w, v) + return w.Buffer.BuildBytes(), w.Error } -func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgEs(out *jwriter.Writer, in es.ErrorT) { - out.RawByte('{') - first := true - _ = first - { - const prefix string = ",\"type\":" - out.RawString(prefix[1:]) - out.String(string(in.Type)) - } - { - const prefix string = ",\"reason\":" - out.RawString(prefix) - out.String(string(in.Reason)) - } - { - const prefix string = ",\"caused_by\":" - out.RawString(prefix) - easyjsonCef4e921Encode(out, in.Cause) - } - out.RawByte('}') + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v bulkStubItem) MarshalEasyJSON(w *jwriter.Writer) { + easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk(w, v) } -func easyjsonCef4e921Decode(in *jlexer.Lexer, out *struct { - Type string `json:"type"` - Reason string `json:"reason"` -}) { - isTopLevel := in.IsStart() - if in.IsNull() { - if isTopLevel { - in.Consumed() - } - in.Skip() - return - } - in.Delim('{') - for !in.IsDelim('}') { - key := in.UnsafeFieldName(false) - in.WantColon() - if in.IsNull() { - in.Skip() - in.WantComma() - continue - } - switch key { - case "type": - out.Type = string(in.String()) - case "reason": - out.Reason = string(in.String()) - default: - in.SkipRecursive() - } - in.WantComma() - } - in.Delim('}') - if isTopLevel { - in.Consumed() - } + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *bulkStubItem) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk(&r, v) + return r.Error() } -func easyjsonCef4e921Encode(out *jwriter.Writer, in struct { - Type string `json:"type"` - Reason string `json:"reason"` -}) { - out.RawByte('{') - first := true - _ = first - { - const prefix string = ",\"type\":" - out.RawString(prefix[1:]) - out.String(string(in.Type)) - } - { - const prefix string = ",\"reason\":" - out.RawString(prefix) - out.String(string(in.Reason)) - } - out.RawByte('}') + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *bulkStubItem) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk(l, v) } -func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk3(in *jlexer.Lexer, out *MsearchResponse) { +func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk1(in *jlexer.Lexer, out *bulkIndexerResponse) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -437,31 +176,33 @@ func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk3(in *jle continue } switch key { - case "responses": + case "took": + out.Took = int(in.Int()) + case "errors": + out.HasErrors = bool(in.Bool()) + case "items": if in.IsNull() { in.Skip() - out.Responses = nil + out.Items = nil } else { in.Delim('[') - if out.Responses == nil { + if out.Items == nil { if !in.IsDelim(']') { - out.Responses = make([]MsearchResponseItem, 0, 0) + out.Items = make([]bulkStubItem, 0, 2) } else { - out.Responses = []MsearchResponseItem{} + out.Items = []bulkStubItem{} } } else { - out.Responses = (out.Responses)[:0] + out.Items = (out.Items)[:0] } for !in.IsDelim(']') { - var v4 MsearchResponseItem - easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk4(in, &v4) - out.Responses = append(out.Responses, v4) + var v1 bulkStubItem + (v1).UnmarshalEasyJSON(in) + out.Items = append(out.Items, v1) in.WantComma() } in.Delim(']') } - case "took": - out.Took = int(in.Int()) default: in.SkipRecursive() } @@ -472,58 +213,61 @@ func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk3(in *jle in.Consumed() } } -func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk3(out *jwriter.Writer, in MsearchResponse) { +func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk1(out *jwriter.Writer, in bulkIndexerResponse) { out.RawByte('{') first := true _ = first { - const prefix string = ",\"responses\":" + const prefix string = ",\"took\":" out.RawString(prefix[1:]) - if in.Responses == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 { - out.RawString("null") - } else { + out.Int(int(in.Took)) + } + { + const prefix string = ",\"errors\":" + out.RawString(prefix) + out.Bool(bool(in.HasErrors)) + } + if len(in.Items) != 0 { + const prefix string = ",\"items\":" + out.RawString(prefix) + { out.RawByte('[') - for v5, v6 := range in.Responses { - if v5 > 0 { + for v2, v3 := range in.Items { + if v2 > 0 { out.RawByte(',') } - easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk4(out, v6) + (v3).MarshalEasyJSON(out) } out.RawByte(']') } } - { - const prefix string = ",\"took\":" - out.RawString(prefix) - out.Int(int(in.Took)) - } out.RawByte('}') } // MarshalJSON supports json.Marshaler interface -func (v MsearchResponse) MarshalJSON() ([]byte, error) { +func (v bulkIndexerResponse) MarshalJSON() ([]byte, error) { w := jwriter.Writer{} - easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk3(&w, v) + easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk1(&w, v) return w.Buffer.BuildBytes(), w.Error } // MarshalEasyJSON supports easyjson.Marshaler interface -func (v MsearchResponse) MarshalEasyJSON(w *jwriter.Writer) { - easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk3(w, v) +func (v bulkIndexerResponse) MarshalEasyJSON(w *jwriter.Writer) { + easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk1(w, v) } // UnmarshalJSON supports json.Unmarshaler interface -func (v *MsearchResponse) UnmarshalJSON(data []byte) error { +func (v *bulkIndexerResponse) UnmarshalJSON(data []byte) error { r := jlexer.Lexer{Data: data} - easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk3(&r, v) + easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk1(&r, v) return r.Error() } // UnmarshalEasyJSON supports easyjson.Unmarshaler interface -func (v *MsearchResponse) UnmarshalEasyJSON(l *jlexer.Lexer) { - easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk3(l, v) +func (v *bulkIndexerResponse) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk1(l, v) } -func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk4(in *jlexer.Lexer, out *MsearchResponseItem) { +func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk2(in *jlexer.Lexer, out *MsearchResponseItem) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -549,9 +293,9 @@ func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk4(in *jle case "timed_out": out.TimedOut = bool(in.Bool()) case "_shards": - easyjsonCef4e921Decode1(in, &out.Shards) + easyjsonCef4e921Decode(in, &out.Shards) case "hits": - easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgEs1(in, &out.Hits) + easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgEs(in, &out.Hits) case "aggregations": if in.IsNull() { in.Skip() @@ -565,22 +309,16 @@ func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk4(in *jle for !in.IsDelim('}') { key := string(in.String()) in.WantColon() - var v7 es.Aggregation - easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgEs2(in, &v7) - (out.Aggregations)[key] = v7 + var v4 es.Aggregation + easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgEs1(in, &v4) + (out.Aggregations)[key] = v4 in.WantComma() } in.Delim('}') } case "error": - if in.IsNull() { - in.Skip() - out.Error = nil - } else { - if out.Error == nil { - out.Error = new(es.ErrorT) - } - easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgEs(in, out.Error) + if data := in.Raw(); in.Ok() { + in.AddError((out.Error).UnmarshalJSON(data)) } default: in.SkipRecursive() @@ -592,7 +330,7 @@ func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk4(in *jle in.Consumed() } } -func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk4(out *jwriter.Writer, in MsearchResponseItem) { +func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk2(out *jwriter.Writer, in MsearchResponseItem) { out.RawByte('{') first := true _ = first @@ -614,40 +352,64 @@ func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk4(out *jw { const prefix string = ",\"_shards\":" out.RawString(prefix) - easyjsonCef4e921Encode1(out, in.Shards) + easyjsonCef4e921Encode(out, in.Shards) } { const prefix string = ",\"hits\":" out.RawString(prefix) - easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgEs1(out, in.Hits) + easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgEs(out, in.Hits) } if len(in.Aggregations) != 0 { const prefix string = ",\"aggregations\":" out.RawString(prefix) { out.RawByte('{') - v8First := true - for v8Name, v8Value := range in.Aggregations { - if v8First { - v8First = false + v5First := true + for v5Name, v5Value := range in.Aggregations { + if v5First { + v5First = false } else { out.RawByte(',') } - out.String(string(v8Name)) + out.String(string(v5Name)) out.RawByte(':') - easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgEs2(out, v8Value) + easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgEs1(out, v5Value) } out.RawByte('}') } } - if in.Error != nil { + if len(in.Error) != 0 { const prefix string = ",\"error\":" out.RawString(prefix) - easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgEs(out, *in.Error) + out.Raw((in.Error).MarshalJSON()) } out.RawByte('}') } -func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgEs2(in *jlexer.Lexer, out *es.Aggregation) { + +// MarshalJSON supports json.Marshaler interface +func (v MsearchResponseItem) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk2(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v MsearchResponseItem) MarshalEasyJSON(w *jwriter.Writer) { + easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk2(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *MsearchResponseItem) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk2(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *MsearchResponseItem) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk2(l, v) +} +func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgEs1(in *jlexer.Lexer, out *es.Aggregation) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -688,11 +450,11 @@ func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgEs2(in *jlexe out.Buckets = (out.Buckets)[:0] } for !in.IsDelim(']') { - var v9 es.Bucket + var v6 es.Bucket if data := in.Raw(); in.Ok() { - in.AddError((v9).UnmarshalJSON(data)) + in.AddError((v6).UnmarshalJSON(data)) } - out.Buckets = append(out.Buckets, v9) + out.Buckets = append(out.Buckets, v6) in.WantComma() } in.Delim(']') @@ -707,7 +469,7 @@ func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgEs2(in *jlexe in.Consumed() } } -func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgEs2(out *jwriter.Writer, in es.Aggregation) { +func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgEs1(out *jwriter.Writer, in es.Aggregation) { out.RawByte('{') first := true _ = first @@ -731,18 +493,18 @@ func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgEs2(out *jwri out.RawString(prefix) { out.RawByte('[') - for v10, v11 := range in.Buckets { - if v10 > 0 { + for v7, v8 := range in.Buckets { + if v7 > 0 { out.RawByte(',') } - easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgEs3(out, v11) + easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgEs2(out, v8) } out.RawByte(']') } } out.RawByte('}') } -func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgEs3(in *jlexer.Lexer, out *es.Bucket) { +func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgEs2(in *jlexer.Lexer, out *es.Bucket) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -775,7 +537,7 @@ func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgEs3(in *jlexe in.Consumed() } } -func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgEs3(out *jwriter.Writer, in es.Bucket) { +func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgEs2(out *jwriter.Writer, in es.Bucket) { out.RawByte('{') first := true _ = first @@ -791,7 +553,7 @@ func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgEs3(out *jwri } out.RawByte('}') } -func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgEs1(in *jlexer.Lexer, out *es.HitsT) { +func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgEs(in *jlexer.Lexer, out *es.HitsT) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -826,15 +588,15 @@ func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgEs1(in *jlexe out.Hits = (out.Hits)[:0] } for !in.IsDelim(']') { - var v12 es.HitT - easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgEs4(in, &v12) - out.Hits = append(out.Hits, v12) + var v9 es.HitT + easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgEs3(in, &v9) + out.Hits = append(out.Hits, v9) in.WantComma() } in.Delim(']') } case "total": - easyjsonCef4e921Decode2(in, &out.Total) + easyjsonCef4e921Decode1(in, &out.Total) case "max_score": if in.IsNull() { in.Skip() @@ -855,7 +617,7 @@ func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgEs1(in *jlexe in.Consumed() } } -func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgEs1(out *jwriter.Writer, in es.HitsT) { +func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgEs(out *jwriter.Writer, in es.HitsT) { out.RawByte('{') first := true _ = first @@ -866,11 +628,11 @@ func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgEs1(out *jwri out.RawString("null") } else { out.RawByte('[') - for v13, v14 := range in.Hits { - if v13 > 0 { + for v10, v11 := range in.Hits { + if v10 > 0 { out.RawByte(',') } - easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgEs4(out, v14) + easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgEs3(out, v11) } out.RawByte(']') } @@ -878,7 +640,7 @@ func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgEs1(out *jwri { const prefix string = ",\"total\":" out.RawString(prefix) - easyjsonCef4e921Encode2(out, in.Total) + easyjsonCef4e921Encode1(out, in.Total) } { const prefix string = ",\"max_score\":" @@ -891,7 +653,7 @@ func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgEs1(out *jwri } out.RawByte('}') } -func easyjsonCef4e921Decode2(in *jlexer.Lexer, out *struct { +func easyjsonCef4e921Decode1(in *jlexer.Lexer, out *struct { Relation string `json:"relation"` Value uint64 `json:"value"` }) { @@ -927,7 +689,7 @@ func easyjsonCef4e921Decode2(in *jlexer.Lexer, out *struct { in.Consumed() } } -func easyjsonCef4e921Encode2(out *jwriter.Writer, in struct { +func easyjsonCef4e921Encode1(out *jwriter.Writer, in struct { Relation string `json:"relation"` Value uint64 `json:"value"` }) { @@ -946,7 +708,7 @@ func easyjsonCef4e921Encode2(out *jwriter.Writer, in struct { } out.RawByte('}') } -func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgEs4(in *jlexer.Lexer, out *es.HitT) { +func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgEs3(in *jlexer.Lexer, out *es.HitT) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -997,7 +759,7 @@ func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgEs4(in *jlexe in.Consumed() } } -func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgEs4(out *jwriter.Writer, in es.HitT) { +func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgEs3(out *jwriter.Writer, in es.HitT) { out.RawByte('{') first := true _ = first @@ -1037,7 +799,7 @@ func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgEs4(out *jwri } out.RawByte('}') } -func easyjsonCef4e921Decode1(in *jlexer.Lexer, out *struct { +func easyjsonCef4e921Decode(in *jlexer.Lexer, out *struct { Total uint64 `json:"total"` Successful uint64 `json:"successful"` Skipped uint64 `json:"skipped"` @@ -1079,7 +841,7 @@ func easyjsonCef4e921Decode1(in *jlexer.Lexer, out *struct { in.Consumed() } } -func easyjsonCef4e921Encode1(out *jwriter.Writer, in struct { +func easyjsonCef4e921Encode(out *jwriter.Writer, in struct { Total uint64 `json:"total"` Successful uint64 `json:"successful"` Skipped uint64 `json:"skipped"` @@ -1110,6 +872,186 @@ func easyjsonCef4e921Encode1(out *jwriter.Writer, in struct { } out.RawByte('}') } +func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk3(in *jlexer.Lexer, out *MsearchResponse) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeFieldName(false) + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "responses": + if in.IsNull() { + in.Skip() + out.Responses = nil + } else { + in.Delim('[') + if out.Responses == nil { + if !in.IsDelim(']') { + out.Responses = make([]MsearchResponseItem, 0, 0) + } else { + out.Responses = []MsearchResponseItem{} + } + } else { + out.Responses = (out.Responses)[:0] + } + for !in.IsDelim(']') { + var v12 MsearchResponseItem + (v12).UnmarshalEasyJSON(in) + out.Responses = append(out.Responses, v12) + in.WantComma() + } + in.Delim(']') + } + case "took": + out.Took = int(in.Int()) + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk3(out *jwriter.Writer, in MsearchResponse) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"responses\":" + out.RawString(prefix[1:]) + if in.Responses == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 { + out.RawString("null") + } else { + out.RawByte('[') + for v13, v14 := range in.Responses { + if v13 > 0 { + out.RawByte(',') + } + (v14).MarshalEasyJSON(out) + } + out.RawByte(']') + } + } + { + const prefix string = ",\"took\":" + out.RawString(prefix) + out.Int(int(in.Took)) + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v MsearchResponse) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk3(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v MsearchResponse) MarshalEasyJSON(w *jwriter.Writer) { + easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk3(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *MsearchResponse) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk3(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *MsearchResponse) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk3(l, v) +} +func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk4(in *jlexer.Lexer, out *MgetResponseItem) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeFieldName(false) + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "found": + out.Found = bool(in.Bool()) + case "_source": + if data := in.Raw(); in.Ok() { + in.AddError((out.Source).UnmarshalJSON(data)) + } + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk4(out *jwriter.Writer, in MgetResponseItem) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"found\":" + out.RawString(prefix[1:]) + out.Bool(bool(in.Found)) + } + { + const prefix string = ",\"_source\":" + out.RawString(prefix) + out.Raw((in.Source).MarshalJSON()) + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v MgetResponseItem) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk4(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v MgetResponseItem) MarshalEasyJSON(w *jwriter.Writer) { + easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk4(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *MgetResponseItem) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk4(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *MgetResponseItem) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk4(l, v) +} func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk5(in *jlexer.Lexer, out *MgetResponse) { isTopLevel := in.IsStart() if in.IsNull() { @@ -1146,7 +1088,7 @@ func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk5(in *jle } for !in.IsDelim(']') { var v15 MgetResponseItem - easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk6(in, &v15) + (v15).UnmarshalEasyJSON(in) out.Items = append(out.Items, v15) in.WantComma() } @@ -1177,7 +1119,7 @@ func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk5(out *jw if v16 > 0 { out.RawByte(',') } - easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk6(out, v17) + (v17).MarshalEasyJSON(out) } out.RawByte(']') } @@ -1208,7 +1150,7 @@ func (v *MgetResponse) UnmarshalJSON(data []byte) error { func (v *MgetResponse) UnmarshalEasyJSON(l *jlexer.Lexer) { easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk5(l, v) } -func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk6(in *jlexer.Lexer, out *MgetResponseItem) { +func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk6(in *jlexer.Lexer, out *BulkIndexerResponseItem) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -1227,11 +1169,13 @@ func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk6(in *jle continue } switch key { - case "found": - out.Found = bool(in.Bool()) - case "_source": + case "_id": + out.DocumentID = string(in.String()) + case "status": + out.Status = int(in.Int()) + case "error": if data := in.Raw(); in.Ok() { - in.AddError((out.Source).UnmarshalJSON(data)) + in.AddError((out.Error).UnmarshalJSON(data)) } default: in.SkipRecursive() @@ -1243,19 +1187,48 @@ func easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk6(in *jle in.Consumed() } } -func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk6(out *jwriter.Writer, in MgetResponseItem) { +func easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk6(out *jwriter.Writer, in BulkIndexerResponseItem) { out.RawByte('{') first := true _ = first { - const prefix string = ",\"found\":" + const prefix string = ",\"_id\":" out.RawString(prefix[1:]) - out.Bool(bool(in.Found)) + out.String(string(in.DocumentID)) } { - const prefix string = ",\"_source\":" + const prefix string = ",\"status\":" out.RawString(prefix) - out.Raw((in.Source).MarshalJSON()) + out.Int(int(in.Status)) + } + if len(in.Error) != 0 { + const prefix string = ",\"error\":" + out.RawString(prefix) + out.Raw((in.Error).MarshalJSON()) } out.RawByte('}') } + +// MarshalJSON supports json.Marshaler interface +func (v BulkIndexerResponseItem) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk6(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v BulkIndexerResponseItem) MarshalEasyJSON(w *jwriter.Writer) { + easyjsonCef4e921EncodeGithubComElasticFleetServerV7InternalPkgBulk6(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *BulkIndexerResponseItem) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk6(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *BulkIndexerResponseItem) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjsonCef4e921DecodeGithubComElasticFleetServerV7InternalPkgBulk6(l, v) +} diff --git a/internal/pkg/dl/actions.go b/internal/pkg/dl/actions.go index 63719e4cf7..4f5b0b445a 100644 --- a/internal/pkg/dl/actions.go +++ b/internal/pkg/dl/actions.go @@ -152,7 +152,7 @@ func DeleteExpiredForIndex(ctx context.Context, index string, bulker bulk.Bulk, } if res.IsError() { - err = es.TranslateError(res.StatusCode, &esres.Error) + err = es.TranslateError(res.StatusCode, esres.Error) if err != nil { if errors.Is(err, es.ErrIndexNotFound) { log.Debug().Str("index", index).Msg(es.ErrIndexNotFound.Error()) diff --git a/internal/pkg/es/delete.go b/internal/pkg/es/delete.go index 708c5df0a9..6d04953f93 100644 --- a/internal/pkg/es/delete.go +++ b/internal/pkg/es/delete.go @@ -26,7 +26,7 @@ func DeleteIndices(ctx context.Context, es *elasticsearch.Client, indices []stri return err } if !ares.Acknowledged { - err = TranslateError(res.StatusCode, &ares.Error) + err = TranslateError(res.StatusCode, ares.Error) } return err diff --git a/internal/pkg/es/error.go b/internal/pkg/es/error.go index a5e575df56..0ba2d76a83 100644 --- a/internal/pkg/es/error.go +++ b/internal/pkg/es/error.go @@ -5,11 +5,19 @@ package es import ( + "encoding/json" "errors" "strconv" "strings" ) +const ( + unknownErrorType = "unknown_error" + timeoutErrorType = "timeout_exception" + indexNotFoundErrorType = "index_not_found_exception" + versionConflictErrorType = "version_conflict_engine_exception" +) + // TODO: Why do we have both ErrElastic and ErrorT? Very strange. type ErrElastic struct { @@ -23,9 +31,9 @@ type ErrElastic struct { } func (e *ErrElastic) Unwrap() error { - if e.Type == "index_not_found_exception" { + if e.Type == indexNotFoundErrorType { return ErrIndexNotFound - } else if e.Type == "timeout_exception" { + } else if e.Type == timeoutErrorType { return ErrTimeout } @@ -66,12 +74,77 @@ var ( ErrIndexNotFound = errors.New("index not found") ErrTimeout = errors.New("timeout") ErrNotFound = errors.New("not found") + + knownErrorTypes = [3]string{ + timeoutErrorType, + indexNotFoundErrorType, + versionConflictErrorType, + } + + // helps with native translation of native java exceptions + // list possible exceptions is much broader, these we recognize. + // all listed here: https://github.com/elastic/elasticsearch/blob/f8d1d2afa67afd1b9769751fde35f86c5ec885d9/server/src/main/java/org/elasticsearch/ElasticsearchException.java#L730 + errorTranslationMap = map[string]string{ + ErrIndexNotFound.Error(): indexNotFoundErrorType, + "IndexNotFoundException": indexNotFoundErrorType, + ErrTimeout.Error(): timeoutErrorType, + "ElasticsearchTimeoutException": timeoutErrorType, + "ProcessClusterEventTimeoutException": timeoutErrorType, + "ReceiveTimeoutTransportException": timeoutErrorType, + ErrElasticVersionConflict.Error(): versionConflictErrorType, + "VersionConflictEngineException": versionConflictErrorType, + } ) -func TranslateError(status int, e *ErrorT) error { +func TranslateError(status int, rawError json.RawMessage) error { if status == 200 || status == 201 { return nil } + + if len(rawError) == 0 { + // error was omitted + return &ErrElastic{ + Status: status, + } + } + + // try decoding detailed error by default + detailedError := &ErrorT{} + if err := json.Unmarshal(rawError, &detailedError); err == nil { + return translateDetailedError(status, detailedError) + } + + reason := string(rawError) + eType := errType(reason) + switch eType { + case versionConflictErrorType: + return ErrElasticVersionConflict + default: + return &ErrElastic{ + Status: status, + Type: eType, + Reason: reason, + } + } +} + +func errType(errBody string) string { + for _, errCheck := range knownErrorTypes { + if strings.Contains(errBody, errCheck) { + return errCheck + } + } + + for errCheck, errType := range errorTranslationMap { + if strings.Contains(errBody, errCheck) { + return errType + } + } + + return unknownErrorType +} + +func translateDetailedError(status int, e *ErrorT) error { if e == nil { return &ErrElastic{ Status: status, @@ -80,7 +153,7 @@ func TranslateError(status int, e *ErrorT) error { var err error switch e.Type { - case "version_conflict_engine_exception": + case versionConflictErrorType: err = ErrElasticVersionConflict default: err = &ErrElastic{ diff --git a/internal/pkg/es/error_test.go b/internal/pkg/es/error_test.go new file mode 100644 index 0000000000..4b50dc3b99 --- /dev/null +++ b/internal/pkg/es/error_test.go @@ -0,0 +1,216 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +//go:build !integration +// +build !integration + +package es + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestErrorTranslation(t *testing.T) { + testCases := []struct { + Status int + Name string + Payload []byte + IsErrorExpected bool + ExpectedType string + ExpectedReason string + }{ + {200, "ok error", []byte("this is ignored"), false, "", ""}, + { + 500, + "nil error", + nil, + true, + "", + "", + }, + { + 500, + "empty error", + []byte{}, + true, + "", + "", + }, + { + 500, + "unknown error", + []byte("this will be unknown"), + true, + unknownErrorType, + "this will be unknown", + }, + { + 500, + "version conflict error", + []byte("this will have elastic version conflict included"), + true, + versionConflictErrorType, + "this will have elastic version conflict included", + }, + { + 500, + "elastic not found error", + []byte("this will have elastic not found included"), + true, + unknownErrorType, + "this will have elastic not found included", + }, + { + 500, + "invalid body error", + []byte("this will have invalid body included"), + true, + unknownErrorType, + "this will have invalid body included", + }, + { + 500, + "index not found error", + []byte("this will have index not found included"), + true, + indexNotFoundErrorType, + "this will have index not found included", + }, + { + 500, + "timeout error", + []byte("this will have timeout included"), + true, + timeoutErrorType, + "this will have timeout included", + }, + { + 500, + "not found error", + []byte("this will have generic not found included"), + true, + unknownErrorType, + "this will have generic not found included", + }, + { + 500, + "timeout_exception error", + []byte("this will have timeout_exception included"), + true, + timeoutErrorType, + "this will have timeout_exception included", + }, + { + 500, + "index_not_found_exception error", + []byte("this will have index_not_found_exception included"), + true, + indexNotFoundErrorType, + "this will have index_not_found_exception included", + }, + { + 500, + "version_conflict_engine_exception error", + []byte("this will have version_conflict_engine_exception included"), + true, + versionConflictErrorType, + "this will have version_conflict_engine_exception included", + }, + { + 500, + "detailed versioned conflict error", + errorTinBytes(ErrorT{ + Type: "version_conflict_engine_exception", + Reason: "some reason", + }), + true, + "version_conflict_engine_exception", + "some reason", + }, + { + 500, + "detailed index not found error", + errorTinBytes(ErrorT{ + Type: "index_not_found_exception", + Reason: "some reason", + }), + true, + "index_not_found_exception", + "some reason", + }, + { + 500, + "detailed timeout conflict error", + errorTinBytes(ErrorT{ + Type: "timeout_exception", + Reason: "some reason", + }), + true, + "timeout_exception", + "some reason", + }, + { + 404, + "detailed index not found json", + []byte(`{ + "root_cause": [ + { + "type": "index_not_found_exception", + "reason": "no such index [.fleet-actions]", + "resource.type": "index_expression", + "resource.id": ".fleet-actions", + "index_uuid": "_na_", + "index": ".fleet-actions" + } + ], + "type": "index_not_found_exception", + "reason": "no such index [.fleet-actions]", + "resource.type": "index_expression", + "resource.id": ".fleet-actions", + "index_uuid": "_na_", + "index": ".fleet-actions" + }`), + true, + indexNotFoundErrorType, + `no such index [.fleet-actions]`, + }, + { + 404, + "index not found json", + []byte("IndexNotFoundException[no such index [.fleet-actions]]"), + true, + indexNotFoundErrorType, + "IndexNotFoundException[no such index [.fleet-actions]]", + }, + } + + for _, tc := range testCases { + t.Run(tc.Name, func(t *testing.T) { + err := TranslateError(tc.Status, tc.Payload) + if !tc.IsErrorExpected { + require.True(t, err == nil, "error not expected but returned") + return + } + + require.True(t, err != nil, "error is expected but not returned") + + if tc.ExpectedType == versionConflictErrorType { + require.Equal(t, ErrElasticVersionConflict, err) + return + } + elasticErr, ok := err.(*ErrElastic) + require.True(t, ok, "elastic error is required") + require.Equal(t, tc.ExpectedType, elasticErr.Type) + require.Equal(t, tc.ExpectedReason, elasticErr.Reason) + }) + } +} + +func errorTinBytes(e ErrorT) []byte { + b, _ := json.Marshal(e) + return b +} diff --git a/internal/pkg/es/info.go b/internal/pkg/es/info.go index 7dad0c7ff4..e7a3d16941 100644 --- a/internal/pkg/es/info.go +++ b/internal/pkg/es/info.go @@ -17,8 +17,8 @@ type versionInfo struct { } type infoResponse struct { - Version versionInfo `json:"version"` - Error ErrorT `json:"error,omitempty"` + Version versionInfo `json:"version"` + Error json.RawMessage `json:"error,omitempty"` } func FetchESVersion(ctx context.Context, esCli *elasticsearch.Client) (version string, err error) { @@ -39,7 +39,7 @@ func FetchESVersion(ctx context.Context, esCli *elasticsearch.Client) (version s } // Check error - err = TranslateError(res.StatusCode, &sres.Error) + err = TranslateError(res.StatusCode, sres.Error) if err != nil { return } diff --git a/internal/pkg/es/result.go b/internal/pkg/es/result.go index b6ee0d2adf..50a03dfc13 100644 --- a/internal/pkg/es/result.go +++ b/internal/pkg/es/result.go @@ -22,8 +22,8 @@ type ErrorT struct { // Acknowledgement response type AckResponse struct { - Acknowledged bool `json:"acknowledged"` - Error ErrorT `json:"error,omitempty"` + Acknowledged bool `json:"acknowledged"` + Error json.RawMessage `json:"error,omitempty"` } type HitT struct { @@ -126,7 +126,7 @@ type Response struct { Hits HitsT `json:"hits"` Aggregations map[string]Aggregation `json:"aggregations,omitempty"` - Error ErrorT `json:"error,omitempty"` + Error json.RawMessage `json:"error,omitempty"` } type DeleteByQueryResponse struct { @@ -135,7 +135,7 @@ type DeleteByQueryResponse struct { TimedOut bool `json:"timed_out"` Deleted int64 `json:"deleted"` - Error ErrorT `json:"error,omitempty"` + Error json.RawMessage `json:"error,omitempty"` } type ResultT struct { diff --git a/internal/pkg/gcheckpt/checkpoint.go b/internal/pkg/gcheckpt/checkpoint.go index f5c4ca2831..6a8bfb8ad7 100644 --- a/internal/pkg/gcheckpt/checkpoint.go +++ b/internal/pkg/gcheckpt/checkpoint.go @@ -26,9 +26,9 @@ var ErrGlobalCheckpoint = errors.New("global checkpoint error") // {"global_checkpoints":[-1]} type globalCheckpointsResponse struct { - GlobalCheckpoints []int64 `json:"global_checkpoints"` - TimedOut bool `json:"timed_out"` - Error esh.ErrorT `json:"error,omitempty"` + GlobalCheckpoints []int64 `json:"global_checkpoints"` + TimedOut bool `json:"timed_out"` + Error json.RawMessage `json:"error,omitempty"` } func Query(ctx context.Context, es *elasticsearch.Client, index string) (seqno sqn.SeqNo, err error) { @@ -82,7 +82,7 @@ func processGlobalCheckpointResponse(res *esapi.Response) (seqno sqn.SeqNo, err } // Check error - err = esh.TranslateError(res.StatusCode, &sres.Error) + err = esh.TranslateError(res.StatusCode, sres.Error) if err != nil { return nil, err } diff --git a/internal/pkg/monitor/monitor.go b/internal/pkg/monitor/monitor.go index 7df89a1d82..690cd114d7 100644 --- a/internal/pkg/monitor/monitor.go +++ b/internal/pkg/monitor/monitor.go @@ -331,7 +331,7 @@ func (m *simpleMonitorT) search(ctx context.Context, tmpl *dsl.Tmpl, params map[ } if res.IsError() { - err = es.TranslateError(res.StatusCode, &esres.Error) + err = es.TranslateError(res.StatusCode, esres.Error) } if err != nil { diff --git a/internal/pkg/testing/setup.go b/internal/pkg/testing/setup.go index 8f38ba7e66..bc881456d2 100644 --- a/internal/pkg/testing/setup.go +++ b/internal/pkg/testing/setup.go @@ -128,7 +128,7 @@ func CleanIndex(ctx context.Context, t *testing.T, bulker bulk.Bulk, index strin } if res.IsError() { - err = es.TranslateError(res.StatusCode, &esres.Error) + err = es.TranslateError(res.StatusCode, esres.Error) if err != nil { if errors.Is(err, es.ErrIndexNotFound) { err = nil