Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix reserved search attribute name validation logic #1398

Merged
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
115 changes: 77 additions & 38 deletions common/searchattribute/defs.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,34 +38,73 @@ const (
ExecutionTime = "ExecutionTime"
CloseTime = "CloseTime"
ExecutionStatus = "ExecutionStatus"

// TODO (alex): move these 3 to non-indexed.
HistoryLength = "HistoryLength"
TaskQueue = "TaskQueue"
Encoding = "Encoding"
TaskQueue = "TaskQueue"

// Valid non-indexed fields on ES.
HistoryLength = "HistoryLength"
Encoding = "Encoding"
Memo = "Memo"
VisibilityTaskKey = "VisibilityTaskKey"

// Attr is prefix of custom search attributes.
// Attr is prefix for search attributes.
Attr = "Attr"
// Custom search attributes.
CustomStringField = "CustomStringField"
CustomKeywordField = "CustomKeywordField"
CustomIntField = "CustomIntField"
CustomDoubleField = "CustomDoubleField"
CustomBoolField = "CustomBoolField"
CustomDatetimeField = "CustomDatetimeField"
// System search attributes.
TemporalChangeVersion = "TemporalChangeVersion"
BinaryChecksums = "BinaryChecksums"
CustomNamespace = "CustomNamespace"
Operator = "Operator"

// Default custom search attributes.
CustomStringField = "CustomStringField"
CustomKeywordField = "CustomKeywordField"
CustomIntField = "CustomIntField"
CustomDoubleField = "CustomDoubleField"
CustomBoolField = "CustomBoolField"
CustomDatetimeField = "CustomDatetimeField"
)

var (
// systemTypeMap is internal system search attributes.
systemTypeMap = map[string]enumspb.IndexedValueType{
// reservedFields are internal field names that can't be used as search attribute names.
reservedFields = map[string]struct{}{
NamespaceID: {},
WorkflowID: {},
RunID: {},
WorkflowType: {},
StartTime: {},
ExecutionTime: {},
CloseTime: {},
ExecutionStatus: {},
TaskQueue: {},

HistoryLength: {},
Encoding: {},
Memo: {},
VisibilityTaskKey: {},
}

// systemSearchAttributes are internal system search attributes which don't require Attr prefix.
systemSearchAttributes = map[string]struct{}{
NamespaceID: {},
WorkflowID: {},
RunID: {},
WorkflowType: {},
StartTime: {},
ExecutionTime: {},
CloseTime: {},
ExecutionStatus: {},
TaskQueue: {},
}

// builtInSearchAttributes are built-in internal search attributes.
builtInSearchAttributes = map[string]struct{}{
TemporalChangeVersion: {},
BinaryChecksums: {},
CustomNamespace: {},
Operator: {},
}

// defaultTypeMap defines default search attributes and their types.
defaultTypeMap = map[string]interface{}{
NamespaceID: enumspb.INDEXED_VALUE_TYPE_KEYWORD,
WorkflowID: enumspb.INDEXED_VALUE_TYPE_KEYWORD,
RunID: enumspb.INDEXED_VALUE_TYPE_KEYWORD,
Expand All @@ -74,41 +113,41 @@ var (
ExecutionTime: enumspb.INDEXED_VALUE_TYPE_INT,
CloseTime: enumspb.INDEXED_VALUE_TYPE_INT,
ExecutionStatus: enumspb.INDEXED_VALUE_TYPE_INT,
HistoryLength: enumspb.INDEXED_VALUE_TYPE_INT,
TaskQueue: enumspb.INDEXED_VALUE_TYPE_KEYWORD,
Encoding: enumspb.INDEXED_VALUE_TYPE_KEYWORD,
}

// defaultTypeMap defines all search attributes.
defaultTypeMap = newDefaultTypeMap()
)
CustomStringField: enumspb.INDEXED_VALUE_TYPE_STRING,
CustomKeywordField: enumspb.INDEXED_VALUE_TYPE_KEYWORD,
CustomIntField: enumspb.INDEXED_VALUE_TYPE_INT,
CustomDoubleField: enumspb.INDEXED_VALUE_TYPE_DOUBLE,
CustomBoolField: enumspb.INDEXED_VALUE_TYPE_BOOL,
CustomDatetimeField: enumspb.INDEXED_VALUE_TYPE_DATETIME,

func newDefaultTypeMap() map[string]interface{} {
result := map[string]interface{}{
CustomStringField: enumspb.INDEXED_VALUE_TYPE_STRING,
CustomKeywordField: enumspb.INDEXED_VALUE_TYPE_KEYWORD,
CustomIntField: enumspb.INDEXED_VALUE_TYPE_INT,
CustomDoubleField: enumspb.INDEXED_VALUE_TYPE_DOUBLE,
CustomBoolField: enumspb.INDEXED_VALUE_TYPE_BOOL,
CustomDatetimeField: enumspb.INDEXED_VALUE_TYPE_DATETIME,
TemporalChangeVersion: enumspb.INDEXED_VALUE_TYPE_KEYWORD,
BinaryChecksums: enumspb.INDEXED_VALUE_TYPE_KEYWORD,
CustomNamespace: enumspb.INDEXED_VALUE_TYPE_KEYWORD,
Operator: enumspb.INDEXED_VALUE_TYPE_KEYWORD,
}
for k, v := range systemTypeMap {
result[k] = v
}
return result
)

// IsReservedField return true if field name is system reserved.
func IsReservedField(fieldName string) bool {
_, ok := reservedFields[fieldName]
return ok
}

// GetDefaultTypeMap return default valid search attributes.
func GetDefaultTypeMap() map[string]interface{} {
return defaultTypeMap
// IsBuiltIn return true if search attribute is system built-in.
func IsBuiltIn(saName string) bool {
_, ok := builtInSearchAttributes[saName]
return ok
}

// IsSystem return true if search attribute is system.
// IsSystem return true if search attribute is system and doesn't require Attr prefix.
func IsSystem(saName string) bool {
_, ok := systemTypeMap[saName]
_, ok := systemSearchAttributes[saName]
return ok
}

// GetDefaultTypeMap return default valid search attributes.
func GetDefaultTypeMap() map[string]interface{} {
return defaultTypeMap
}
4 changes: 2 additions & 2 deletions common/searchattribute/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ func (v *Validator) Validate(searchAttributes *commonpb.SearchAttributes, namesp
}

// verify: saName is not system reserved
if IsSystem(saName) {
return serviceerror.NewInvalidArgument(fmt.Sprintf("%s is read-only Temporal reserved search attribute", saName))
if IsReservedField(saName) {
return serviceerror.NewInvalidArgument(fmt.Sprintf("%s is Temporal reserved field name", saName))
}
// verify: size of single value <= limit
dataSize := len(saPayload.GetData())
Expand Down
2 changes: 1 addition & 1 deletion common/searchattribute/validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ func (s *searchAttributesValidatorSuite) TestValidateSearchAttributes() {
}
attr.IndexedFields = fields
err = validator.Validate(attr, namespace)
s.Equal("StartTime is read-only Temporal reserved search attribute", err.Error())
s.Equal("StartTime is Temporal reserved field name", err.Error())

fields = map[string]*commonpb.Payload{
"CustomKeywordField": payload.EncodeString("123456"),
Expand Down
2 changes: 0 additions & 2 deletions config/dynamicconfig/development_es.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,7 @@ frontend.validSearchAttributes:
ExecutionTime: "Int"
CloseTime: "Int"
ExecutionStatus: "Int"
HistoryLength: "Int"
TaskQueue: "Keyword"
Encoding: "Keyword"
CustomStringField: "String"
CustomKeywordField: "Keyword"
CustomIntField: "Int"
Expand Down
8 changes: 1 addition & 7 deletions schema/elasticsearch/v6/visibility/index_template.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,10 @@
"ExecutionStatus": {
"type": "long"
},

"HistoryLength": {
"type": "long"
},
"Encoding": {
"type": "keyword"
},
"TaskQueue": {
"type": "keyword"
},

"Attr": {
"properties": {
"TemporalChangeVersion": { "type": "keyword" },
Expand Down
8 changes: 1 addition & 7 deletions schema/elasticsearch/v7/visibility/index_template.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,10 @@
"ExecutionStatus": {
"type": "long"
},

"HistoryLength": {
"type": "long"
},
"Encoding": {
"type": "keyword"
},
"TaskQueue": {
"type": "keyword"
},

"Attr": {
"properties": {
"TemporalChangeVersion": {
Expand Down
2 changes: 1 addition & 1 deletion service/frontend/adminHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ func (adh *AdminHandler) AddSearchAttribute(ctx context.Context, request *admins
currentValidAttr, _ := adh.params.DynamicConfig.GetMapValue(
dynamicconfig.ValidSearchAttributes, nil, searchattribute.GetDefaultTypeMap())
for k, v := range searchAttr {
if searchattribute.IsSystem(k) {
if searchattribute.IsReservedField(k) || searchattribute.IsBuiltIn(k) {
return nil, adh.error(serviceerror.NewInvalidArgument(fmt.Sprintf(errKeyIsReservedBySystemMessage, k)), scope)
}
if _, exist := currentValidAttr[k]; exist {
Expand Down