Skip to content

Commit 6880f8e

Browse files
authored
Multi-namespace search attribute config format (#95)
1 parent 1ba01d6 commit 6880f8e

4 files changed

Lines changed: 116 additions & 21 deletions

File tree

config/config.go

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,26 @@ type (
111111
MuxTransports []MuxTransportConfig `yaml:"mux"`
112112
HealthCheck *HealthCheckConfig `yaml:"healthCheck"`
113113
NamespaceNameTranslation NameTranslationConfig `yaml:"namespaceNameTranslation"`
114-
SearchAttributeTranslation NameTranslationConfig `yaml:"searchAttributeTranslation"`
114+
SearchAttributeTranslation SATranslationConfig `yaml:"searchAttributeTranslation"`
115115
Metrics *MetricsConfig `yaml:"metrics"`
116116
ProfilingConfig ProfilingConfig `yaml:"profiling"`
117117
}
118118

119+
SATranslationConfig struct {
120+
NamespaceMappings []SANamespaceMapping `yaml:"namespaceMappings"`
121+
}
122+
123+
SANamespaceMapping struct {
124+
Name string `yaml:"name"`
125+
NamespaceId string `yaml:"namespaceId"`
126+
Mappings []SAMapping `yaml:"mappings"`
127+
}
128+
129+
SAMapping struct {
130+
LocalName string `yaml:"localFieldName"`
131+
RemoteName string `yaml:"remoteFieldName"`
132+
}
133+
119134
ProfilingConfig struct {
120135
PProfHTTPAddress string `yaml:"pprofAddress"`
121136
}
@@ -320,3 +335,36 @@ func (c *ProfilingConfig) UnmarshalYAML(unmarshal func(interface{}) error) error
320335
type plain ProfilingConfig
321336
return unmarshal((*plain)(c))
322337
}
338+
339+
func (s SATranslationConfig) IsEnabled() bool {
340+
return len(s.NamespaceMappings) > 0
341+
}
342+
343+
// ToMaps returns request and response mappings.
344+
func (s SATranslationConfig) ToMaps(inBound bool) (map[string]map[string]string, map[string]map[string]string) {
345+
reqMap := make(map[string]map[string]string)
346+
respMap := make(map[string]map[string]string)
347+
for _, ns := range s.NamespaceMappings {
348+
reqMap[ns.NamespaceId] = make(map[string]string, len(ns.Mappings))
349+
respMap[ns.NamespaceId] = make(map[string]string, len(ns.Mappings))
350+
351+
if inBound {
352+
// For inbound listener,
353+
// - incoming requests from remote server are modifed to match local server
354+
// - outgoing responses to local server are modified to match remote server
355+
for _, tr := range ns.Mappings {
356+
reqMap[ns.NamespaceId][tr.RemoteName] = tr.LocalName
357+
respMap[ns.NamespaceId][tr.LocalName] = tr.RemoteName
358+
}
359+
} else {
360+
// For outbound listener,
361+
// - incoming requests from local server are modifed to match remote server
362+
// - outgoing responses to remote server are modified to match local server
363+
for _, tr := range ns.Mappings {
364+
reqMap[ns.NamespaceId][tr.LocalName] = tr.RemoteName
365+
respMap[ns.NamespaceId][tr.RemoteName] = tr.LocalName
366+
}
367+
}
368+
}
369+
return reqMap, respMap
370+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package interceptor
2+
3+
import (
4+
"strings"
5+
6+
"go.temporal.io/server/common/api"
7+
)
8+
9+
type (
10+
saTranslator struct {
11+
matchMethod func(string) bool
12+
reqMap map[string]stringMatcher
13+
respMap map[string]stringMatcher
14+
}
15+
)
16+
17+
func NewSearchAttributeTranslator(reqMap, respMap map[string]map[string]string) Translator {
18+
return &saTranslator{
19+
matchMethod: func(method string) bool {
20+
// In workflowservice APIs, responses only contain the search attribute alias.
21+
// We should never translate these responses to the search attribute's indexed field.
22+
return !strings.HasPrefix(method, api.WorkflowServicePrefix)
23+
},
24+
reqMap: createStringMatchers(reqMap),
25+
respMap: createStringMatchers(respMap),
26+
}
27+
}
28+
29+
func (s *saTranslator) MatchMethod(m string) bool {
30+
return s.matchMethod(m)
31+
}
32+
33+
func (s *saTranslator) TranslateRequest(req any) (bool, error) {
34+
return visitSearchAttributes(req, s.getNamespaceReqMatcher(""))
35+
}
36+
37+
func (s *saTranslator) TranslateResponse(resp any) (bool, error) {
38+
return visitSearchAttributes(resp, s.getNamespaceRespMatcher(""))
39+
}
40+
41+
func (s *saTranslator) getNamespaceReqMatcher(namespaceId string) stringMatcher {
42+
// Placeholder: Just return the first one (only support one namespace mapping)
43+
for _, matcher := range s.reqMap {
44+
return matcher
45+
}
46+
return createStringMatcher(nil)
47+
}
48+
49+
func (s *saTranslator) getNamespaceRespMatcher(namespaceId string) stringMatcher {
50+
// Placeholder: Just return the first one (only support one namespace mappping)
51+
for _, matcher := range s.respMap {
52+
return matcher
53+
}
54+
return createStringMatcher(nil)
55+
}
56+
57+
func createStringMatchers(nsMappings map[string]map[string]string) map[string]stringMatcher {
58+
result := make(map[string]stringMatcher, len(nsMappings))
59+
for nsId, mapping := range nsMappings {
60+
result[nsId] = createStringMatcher(mapping)
61+
}
62+
return result
63+
}

interceptor/translator.go

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
11
package interceptor
22

3-
import (
4-
"strings"
5-
6-
"go.temporal.io/server/common/api"
7-
)
8-
93
type (
104
Translator interface {
115
MatchMethod(string) bool
@@ -30,19 +24,6 @@ func NewNamespaceNameTranslator(reqMap, respMap map[string]string) Translator {
3024
}
3125
}
3226

33-
func NewSearchAttributeTranslator(reqMap, respMap map[string]string) Translator {
34-
return &translatorImpl{
35-
matchMethod: func(method string) bool {
36-
// In workflowservice APIs, responses only contain the search attribute alias.
37-
// We should never translate these responses to the search attribute's indexed field.
38-
return !strings.HasPrefix(method, api.WorkflowServicePrefix)
39-
},
40-
matchReq: createStringMatcher(reqMap),
41-
matchResp: createStringMatcher(respMap),
42-
visitor: visitSearchAttributes,
43-
}
44-
}
45-
4627
func (n *translatorImpl) MatchMethod(m string) bool {
4728
return n.matchMethod(m)
4829
}

proxy/proxy.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,10 @@ func makeServerOptions(
6161
}
6262

6363
if tln := proxyOpts.Config.SearchAttributeTranslation; tln.IsEnabled() {
64-
logger.Info("search attribute translation enabled", tag.NewAnyTag("mappings", tln.Mappings))
64+
logger.Info("search attribute translation enabled", tag.NewAnyTag("mappings", tln.NamespaceMappings))
65+
if len(tln.NamespaceMappings) > 1 {
66+
panic("multiple namespace search attribute mappings are not supported")
67+
}
6568
translators = append(translators,
6669
interceptor.NewSearchAttributeTranslator(tln.ToMaps(proxyOpts.IsInbound)))
6770
}

0 commit comments

Comments
 (0)