Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions internal/fields/dependency_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,9 +201,8 @@ func (dm *DependencyManager) injectFieldsWithOptions(defs []common.MapStr, optio
transformed.Delete("external")
}

// Allow to override the type only from keyword to constant_keyword,
// to support the case of setting the value already in the mappings.
if ttype, _ := transformed["type"].(string); ttype != "constant_keyword" || imported.Type != "keyword" {
// Set the type back to the one imported, unless it is one of the allowed overrides.
if ttype, _ := transformed["type"].(string); !allowedTypeOverride(imported.Type, ttype) {
transformed["type"] = imported.Type
}

Expand Down Expand Up @@ -264,6 +263,28 @@ func skipField(def common.MapStr) bool {
return false
}

func allowedTypeOverride(fromType, toType string) bool {
allowed := []struct {
from string
to string
}{
// Support the case of setting the value already in the mappings.
{"keyword", "constant_keyword"},

// Support objects in ECS where the developer must decide if using
// a group or nested object.
{"object", "group"},
{"object", "nested"},
}

for _, a := range allowed {
if a.from == fromType && a.to == toType {
return true
}
}
return false
}

// importField method resolves dependency on a single external field using available schemas.
func (dm *DependencyManager) importField(schemaName, fieldPath string) (FieldDefinition, error) {
if dm == nil {
Expand Down
38 changes: 38 additions & 0 deletions internal/fields/dependency_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,44 @@ func TestDependencyManagerWithECS(t *testing.T) {
},
},
},
{
title: "object to nested override",
defs: []common.MapStr{
{
"name": "dns.answers",
"external": "ecs",
"type": "nested",
},
},
options: InjectFieldsOptions{},
valid: true,
result: []common.MapStr{
{
"name": "dns.answers",
"description": "An array containing an object for each answer section returned by the server.\nThe main keys that should be present in these objects are defined by ECS. Records that have more information may contain more keys than what ECS defines.\nNot all DNS data sources give all details about DNS answers. At minimum, answer objects must contain the `data` key. If more information is available, map as much of it to ECS as possible, and add any additional fields to the answer objects as custom fields.",
"type": "nested",
},
},
},
{
title: "object to group override",
defs: []common.MapStr{
{
"name": "dns.answers",
"external": "ecs",
"type": "group",
},
},
options: InjectFieldsOptions{},
valid: true,
result: []common.MapStr{
{
"name": "dns.answers",
"description": "An array containing an object for each answer section returned by the server.\nThe main keys that should be present in these objects are defined by ECS. Records that have more information may contain more keys than what ECS defines.\nNot all DNS data sources give all details about DNS answers. At minimum, answer objects must contain the `data` key. If more information is available, map as much of it to ECS as possible, and add any additional fields to the answer objects as custom fields.",
"type": "group",
},
},
},
}

for _, c := range cases {
Expand Down