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
66 changes: 39 additions & 27 deletions internal/fields/dependency_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,33 +163,54 @@ func (dm *DependencyManager) injectFieldsWithRoot(root string, defs []common.Map
transformed["type"] = imported.Type
transformed.Delete("external")

updated = append(updated, transformed)
def = transformed
changed = true
continue
}

fields, _ := def.GetValue("fields")
if fields != nil {
fieldsMs, err := common.ToMapStrSlice(fields)
if err != nil {
return nil, false, errors.Wrap(err, "can't convert fields")
}
updatedFields, fieldsChanged, err := dm.injectFieldsWithRoot(fieldPath, fieldsMs)
if err != nil {
return nil, false, err
}

if fieldsChanged {
changed = true
} else {
fields, _ := def.GetValue("fields")
if fields != nil {
fieldsMs, err := common.ToMapStrSlice(fields)
if err != nil {
return nil, false, errors.Wrap(err, "can't convert fields")
}
updatedFields, fieldsChanged, err := dm.injectFieldsWithRoot(fieldPath, fieldsMs)
if err != nil {
return nil, false, err
}

if fieldsChanged {
changed = true
}

def.Put("fields", updatedFields)
}
}

def.Put("fields", updatedFields)
if skipField(def) {
continue
}
updated = append(updated, def)
}
return updated, changed, nil
}

// skipField decides if a field should be skipped and not injected in the built fields.
func skipField(def common.MapStr) bool {
t, _ := def.GetValue("type")
if t == "group" {
fields, _ := def.GetValue("fields")
switch fields := fields.(type) {
case nil:
return true
case []interface{}:
return len(fields) == 0
case []common.MapStr:
return len(fields) == 0
}
}

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 Expand Up @@ -241,15 +262,6 @@ func transformImportedField(fd FieldDefinition) common.MapStr {
m["doc_values"] = *fd.DocValues
}

if len(fd.Fields) > 0 {
var t []common.MapStr
for _, f := range fd.Fields {
i := transformImportedField(f)
t = append(t, i)
}
m.Put("fields", t)
}

if len(fd.MultiFields) > 0 {
var t []common.MapStr
for _, f := range fd.MultiFields {
Expand Down
105 changes: 105 additions & 0 deletions internal/fields/dependency_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,94 @@ func TestDependencyManagerInjectExternalFields(t *testing.T) {
},
valid: false,
},
{
title: "import nested fields",
defs: []common.MapStr{
{
"name": "host.id",
"external": "test",
},
{
"name": "host.hostname",
"external": "test",
},
},
result: []common.MapStr{
{
"name": "host.id",
"description": "Unique host id",
"type": "keyword",
},
{
"name": "host.hostname",
"description": "Hostname of the host",
"type": "keyword",
},
},
valid: true,
changed: true,
},
{
title: "import nested definitions",
defs: []common.MapStr{
{
"name": "host",
"type": "group",
"fields": []interface{}{
common.MapStr{
"name": "id",
"external": "test",
},
common.MapStr{
"name": "hostname",
"external": "test",
},
},
},
},
result: []common.MapStr{
{
"name": "host",
"type": "group",
"fields": []common.MapStr{
{
"name": "id",
"description": "Unique host id",
"type": "keyword",
},
{
"name": "hostname",
"description": "Hostname of the host",
"type": "keyword",
},
},
},
},
valid: true,
changed: true,
},
{
title: "keep group for docs but not for fields",
defs: []common.MapStr{
{
"name": "host",
"external": "test",
},
{
"name": "host.hostname",
"external": "test",
},
},
result: []common.MapStr{
{
"name": "host.hostname",
"description": "Hostname of the host",
"type": "keyword",
},
},
valid: true,
changed: true,
},
}

indexFalse := false
Expand Down Expand Up @@ -253,6 +341,23 @@ func TestDependencyManagerInjectExternalFields(t *testing.T) {
Pattern: "^[A-F0-9]{2}(-[A-F0-9]{2}){5,}$",
Type: "keyword",
},
{
Name: "host",
Description: "A general computing instance",
Type: "group",
Fields: []FieldDefinition{
{
Name: "id",
Description: "Unique host id",
Type: "keyword",
},
{
Name: "hostname",
Description: "Hostname of the host",
Type: "keyword",
},
},
},
}}
dm := &DependencyManager{schema: schema}

Expand Down
2 changes: 2 additions & 0 deletions internal/fields/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,8 @@ func (v *Validator) parseElementValue(key string, definition FieldDefinition, va
}
case "float", "long", "double":
_, valid = val.(float64)
case "group":
return fmt.Errorf("field %q is a group of fields, it cannot store values", key)
default:
valid = true // all other types are considered valid not blocking validation
}
Expand Down
9 changes: 9 additions & 0 deletions internal/fields/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,15 @@ func Test_parseElementValue(t *testing.T) {
},
fail: true,
},
// fields shouldn't be stored in groups
{
key: "host",
value: "42",
definition: FieldDefinition{
Type: "group",
},
fail: true,
},
} {
v := Validator{disabledDependencyManagement: true}
t.Run(test.key, func(t *testing.T) {
Expand Down