序
本文次要钻研一下cortex的tenant
tenant
cortex/pkg/tenant/tenant.go
var ( errTenantIDTooLong = errors.New("tenant ID is too long: max 150 characters"))type errTenantIDUnsupportedCharacter struct { pos int tenantID string}func (e *errTenantIDUnsupportedCharacter) Error() string { return fmt.Sprintf( "tenant ID '%s' contains unsupported character '%c'", e.tenantID, e.tenantID[e.pos], )}const tenantIDsLabelSeparator = "|"// NormalizeTenantIDs is creating a normalized form by sortiing and de-duplicating the list of tenantIDsfunc NormalizeTenantIDs(tenantIDs []string) []string { sort.Strings(tenantIDs) count := len(tenantIDs) if count <= 1 { return tenantIDs } posOut := 1 for posIn := 1; posIn < count; posIn++ { if tenantIDs[posIn] != tenantIDs[posIn-1] { tenantIDs[posOut] = tenantIDs[posIn] posOut++ } } return tenantIDs[0:posOut]}// ValidTenantIDfunc ValidTenantID(s string) error { // check if it contains invalid runes for pos, r := range s { if !isSupported(r) { return &errTenantIDUnsupportedCharacter{ tenantID: s, pos: pos, } } } if len(s) > 150 { return errTenantIDTooLong } return nil}func JoinTenantIDs(tenantIDs []string) string { return strings.Join(tenantIDs, tenantIDsLabelSeparator)}// this checks if a rune is supported in tenant IDs (according to// https://cortexmetrics.io/docs/guides/limitations/#tenant-id-naming)func isSupported(c rune) bool { // characters if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') { return true } // digits if '0' <= c && c <= '9' { return true } // special return c == '!' || c == '-' || c == '_' || c == '.' || c == '*' || c == '\'' || c == '(' || c == ')'}// TenantIDsFromOrgID extracts different tenants from an orgID string value//// ignore stutter warning//nolint:golintfunc TenantIDsFromOrgID(orgID string) ([]string, error) { return TenantIDs(user.InjectOrgID(context.TODO(), orgID))}
tenant提供了NormalizeTenantIDs、ValidTenantID、JoinTenantIDs办法;NormalizeTenantIDs用于去重和排序tenantIDs;ValidTenantID会通过isSupported进行校验,并校验长度;JoinTenantIDs应用|
来连贯TenantID
Resolver
cortex/pkg/tenant/resolver.go
type Resolver interface { // TenantID returns exactly a single tenant ID from the context. It should be // used when a certain endpoint should only support exactly a single // tenant ID. It returns an error user.ErrNoOrgID if there is no tenant ID // supplied or user.ErrTooManyOrgIDs if there are multiple tenant IDs present. TenantID(context.Context) (string, error) // TenantIDs returns all tenant IDs from the context. It should return // normalized list of ordered and distinct tenant IDs (as produced by // NormalizeTenantIDs). TenantIDs(context.Context) ([]string, error)}
Resolver接口定义了TenantID、TenantIDs办法
SingleResolver
cortex/pkg/tenant/resolver.go
type SingleResolver struct {}func (t *SingleResolver) TenantID(ctx context.Context) (string, error) { //lint:ignore faillint wrapper around upstream method return user.ExtractOrgID(ctx)}func (t *SingleResolver) TenantIDs(ctx context.Context) ([]string, error) { //lint:ignore faillint wrapper around upstream method orgID, err := user.ExtractOrgID(ctx) if err != nil { return nil, err } return []string{orgID}, err}
SingleResolver实现了Resolver接口,其TenantID应用user.ExtractOrgID(ctx)提取TenantID;TenantIDs办法则返回的是orgID数组
MultiResolver
cortex/pkg/tenant/resolver.go
type MultiResolver struct {}// NewMultiResolver creates a tenant resolver, which allows request to have// multiple tenant ids submitted separated by a '|' character. This enforces// further limits on the character set allowed within tenants as detailed here:// https://cortexmetrics.io/docs/guides/limitations/#tenant-id-naming)func NewMultiResolver() *MultiResolver { return &MultiResolver{}}func (t *MultiResolver) TenantID(ctx context.Context) (string, error) { orgIDs, err := t.TenantIDs(ctx) if err != nil { return "", err } if len(orgIDs) > 1 { return "", user.ErrTooManyOrgIDs } return orgIDs[0], nil}func (t *MultiResolver) TenantIDs(ctx context.Context) ([]string, error) { //lint:ignore faillint wrapper around upstream method orgID, err := user.ExtractOrgID(ctx) if err != nil { return nil, err } orgIDs := strings.Split(orgID, tenantIDsLabelSeparator) for _, orgID := range orgIDs { if err := ValidTenantID(orgID); err != nil { return nil, err } } return NormalizeTenantIDs(orgIDs), nil}
MultiResolver实现了Resolver接口,其TenantID办法应用TenantIDs提取orgIDs,并校验其长度;TenantIDs办法应用user.ExtractOrgID(ctx)提取orgID,而后应用tenantIDsLabelSeparator宰割提取为orgIDs,最初通过NormalizeTenantIDs返回
小结
cortex的tenant提供了NormalizeTenantIDs、ValidTenantID、JoinTenantIDs办法;Resolver接口定义了TenantID、TenantIDs办法;SingleResolver及MultiResolver都实现了Resolver接口,根本都是通过user.ExtractOrgID(ctx)提取tenantID。
doc
- cortex