345 lines
12 KiB
Go
345 lines
12 KiB
Go
package tenant
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sort"
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
"github.com/influxdata/influxdb/v2"
|
|
"github.com/influxdata/influxdb/v2/kv"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
var _ influxdb.TenantService = (*tenantService)(nil)
|
|
|
|
var bucketCmpOptions = cmp.Options{
|
|
cmp.Transformer("Sort", func(in []*influxdb.Bucket) []*influxdb.Bucket {
|
|
out := append([]*influxdb.Bucket(nil), in...) // Copy input to avoid mutating it
|
|
sort.Slice(out, func(i, j int) bool {
|
|
return out[i].Name > out[j].Name
|
|
})
|
|
return out
|
|
}),
|
|
}
|
|
|
|
// readOnlyStore is a wrapper for kv.Store that ensures that updates are not applied.
|
|
type readOnlyStore struct {
|
|
kv.Store
|
|
}
|
|
|
|
func (r readOnlyStore) Update(context.Context, func(kv.Tx) error) error {
|
|
return nil
|
|
}
|
|
|
|
type tenantService struct {
|
|
log *zap.Logger
|
|
|
|
oldBucketSvc influxdb.BucketService
|
|
newBucketSvc influxdb.BucketService
|
|
oldOrgSvc influxdb.OrganizationService
|
|
newOrgSvc influxdb.OrganizationService
|
|
oldURMSvc influxdb.UserResourceMappingService
|
|
newURMSvc influxdb.UserResourceMappingService
|
|
oldUserSvc influxdb.UserService
|
|
newUserSvc influxdb.UserService
|
|
oldPwdSvc influxdb.PasswordsService
|
|
newPwdSvc influxdb.PasswordsService
|
|
}
|
|
|
|
// NewReadOnlyStore returns a Store that cannot update the underlying kv.Store.
|
|
func NewReadOnlyStore(store kv.Store) (*Store, error) {
|
|
return NewStore(readOnlyStore{Store: store})
|
|
}
|
|
|
|
// NewDuplicateReadTenantService returns a tenant service that duplicates the reads to oldSvc and newSvc.
|
|
// The foreseen use case is to compare two service versions, an old one and a new one.
|
|
// The resulting influxdb.TenantService:
|
|
// - forwards writes to the old service;
|
|
// - reads from the old one, if no error is encountered, it reads from the new one;
|
|
// - compares the results obtained and logs the difference, if any.
|
|
func NewDuplicateReadTenantService(log *zap.Logger, oldSvc, newSvc influxdb.TenantService) influxdb.TenantService {
|
|
return tenantService{
|
|
log: log,
|
|
|
|
oldBucketSvc: oldSvc,
|
|
oldOrgSvc: oldSvc,
|
|
oldURMSvc: oldSvc,
|
|
oldUserSvc: oldSvc,
|
|
oldPwdSvc: oldSvc,
|
|
|
|
newBucketSvc: newSvc,
|
|
newOrgSvc: newSvc,
|
|
newURMSvc: newSvc,
|
|
newUserSvc: newSvc,
|
|
newPwdSvc: newSvc,
|
|
}
|
|
}
|
|
|
|
// NewDuplicateReadBucketService returns a service that duplicates the reads to oldSvc and newSvc.
|
|
func NewDuplicateReadBucketService(log *zap.Logger, oldSvc, newSvc influxdb.BucketService) influxdb.BucketService {
|
|
return tenantService{
|
|
log: log,
|
|
|
|
oldBucketSvc: oldSvc,
|
|
newBucketSvc: newSvc,
|
|
}
|
|
}
|
|
|
|
// NewDuplicateReadOrganizationService returns a service that duplicates the reads to oldSvc and newSvc.
|
|
func NewDuplicateReadOrganizationService(log *zap.Logger, oldSvc, newSvc influxdb.OrganizationService) influxdb.OrganizationService {
|
|
return tenantService{
|
|
log: log,
|
|
|
|
oldOrgSvc: oldSvc,
|
|
newOrgSvc: newSvc,
|
|
}
|
|
}
|
|
|
|
// NewDuplicateReadUserResourceMappingService returns a service that duplicates the reads to oldSvc and newSvc.
|
|
func NewDuplicateReadUserResourceMappingService(log *zap.Logger, oldSvc, newSvc influxdb.UserResourceMappingService) influxdb.UserResourceMappingService {
|
|
return tenantService{
|
|
log: log,
|
|
|
|
oldURMSvc: oldSvc,
|
|
newURMSvc: newSvc,
|
|
}
|
|
}
|
|
|
|
// NewDuplicateReadUserService returns a service that duplicates the reads to oldSvc and newSvc.
|
|
func NewDuplicateReadUserService(log *zap.Logger, oldSvc, newSvc influxdb.UserService) influxdb.UserService {
|
|
return tenantService{
|
|
log: log,
|
|
|
|
oldUserSvc: oldSvc,
|
|
newUserSvc: newSvc,
|
|
}
|
|
}
|
|
|
|
// NewDuplicateReadPasswordsService returns a service that duplicates the reads to oldSvc and newSvc.
|
|
func NewDuplicateReadPasswordsService(log *zap.Logger, oldSvc, newSvc influxdb.PasswordsService) influxdb.PasswordsService {
|
|
return tenantService{
|
|
log: log,
|
|
|
|
oldPwdSvc: oldSvc,
|
|
newPwdSvc: newSvc,
|
|
}
|
|
}
|
|
|
|
func (s tenantService) FindBucketByID(ctx context.Context, id influxdb.ID) (*influxdb.Bucket, error) {
|
|
o, err := s.oldBucketSvc.FindBucketByID(ctx, id)
|
|
if err != nil {
|
|
return o, err
|
|
}
|
|
n, err := s.newBucketSvc.FindBucketByID(ctx, id)
|
|
if err != nil {
|
|
s.log.Error("error in new meta store", zap.Error(err))
|
|
} else if diff := cmp.Diff(o, n); diff != "" {
|
|
s.log.Error(fmt.Sprintf("unexpected read result -old/+new:\n\t%s", diff), zap.String("diff", diff), zap.String("call", "FindBucketByID"))
|
|
}
|
|
return o, nil
|
|
}
|
|
|
|
func (s tenantService) FindBucketByName(ctx context.Context, orgID influxdb.ID, name string) (*influxdb.Bucket, error) {
|
|
o, err := s.oldBucketSvc.FindBucketByName(ctx, orgID, name)
|
|
if err != nil {
|
|
return o, err
|
|
}
|
|
n, err := s.newBucketSvc.FindBucketByName(ctx, orgID, name)
|
|
if err != nil {
|
|
s.log.Error("error in new meta store", zap.Error(err))
|
|
} else if diff := cmp.Diff(o, n); diff != "" {
|
|
s.log.Error(fmt.Sprintf("unexpected read result -old/+new:\n\t%s", diff), zap.String("diff", diff), zap.String("call", "FindBucketByName"))
|
|
}
|
|
return o, nil
|
|
}
|
|
|
|
func (s tenantService) FindBucket(ctx context.Context, filter influxdb.BucketFilter) (*influxdb.Bucket, error) {
|
|
o, err := s.oldBucketSvc.FindBucket(ctx, filter)
|
|
if err != nil {
|
|
return o, err
|
|
}
|
|
n, err := s.newBucketSvc.FindBucket(ctx, filter)
|
|
if err != nil {
|
|
s.log.Error("error in new meta store", zap.Error(err))
|
|
} else if diff := cmp.Diff(o, n); diff != "" {
|
|
s.log.Error(fmt.Sprintf("unexpected read result -old/+new:\n\t%s", diff), zap.String("diff", diff), zap.String("call", "FindBucket"))
|
|
}
|
|
return o, nil
|
|
}
|
|
|
|
func (s tenantService) FindBuckets(ctx context.Context, filter influxdb.BucketFilter, opt ...influxdb.FindOptions) ([]*influxdb.Bucket, int, error) {
|
|
o, no, err := s.oldBucketSvc.FindBuckets(ctx, filter, opt...)
|
|
if err != nil {
|
|
return o, no, err
|
|
}
|
|
n, _, err := s.newBucketSvc.FindBuckets(ctx, filter, opt...)
|
|
if err != nil {
|
|
s.log.Error("error in new meta store", zap.Error(err))
|
|
} else if diff := cmp.Diff(o, n, bucketCmpOptions); diff != "" {
|
|
s.log.Error(fmt.Sprintf("unexpected read result -old/+new:\n\t%s", diff), zap.String("diff", diff), zap.String("call", "FindBuckets"))
|
|
}
|
|
return o, no, nil
|
|
}
|
|
|
|
func (s tenantService) CreateBucket(ctx context.Context, b *influxdb.Bucket) error {
|
|
return s.oldBucketSvc.CreateBucket(ctx, b)
|
|
}
|
|
|
|
func (s tenantService) UpdateBucket(ctx context.Context, id influxdb.ID, upd influxdb.BucketUpdate) (*influxdb.Bucket, error) {
|
|
return s.oldBucketSvc.UpdateBucket(ctx, id, upd)
|
|
}
|
|
|
|
func (s tenantService) DeleteBucket(ctx context.Context, id influxdb.ID) error {
|
|
return s.oldBucketSvc.DeleteBucket(ctx, id)
|
|
}
|
|
|
|
func (s tenantService) FindOrganizationByID(ctx context.Context, id influxdb.ID) (*influxdb.Organization, error) {
|
|
o, err := s.oldOrgSvc.FindOrganizationByID(ctx, id)
|
|
if err != nil {
|
|
return o, err
|
|
}
|
|
n, err := s.newOrgSvc.FindOrganizationByID(ctx, id)
|
|
if err != nil {
|
|
s.log.Error("error in new meta store", zap.Error(err))
|
|
} else if diff := cmp.Diff(o, n); diff != "" {
|
|
s.log.Error(fmt.Sprintf("unexpected read result -old/+new:\n\t%s", diff), zap.String("diff", diff), zap.String("call", "FindOrganizationByID"))
|
|
}
|
|
return o, nil
|
|
}
|
|
|
|
func (s tenantService) FindOrganization(ctx context.Context, filter influxdb.OrganizationFilter) (*influxdb.Organization, error) {
|
|
o, err := s.oldOrgSvc.FindOrganization(ctx, filter)
|
|
if err != nil {
|
|
return o, err
|
|
}
|
|
n, err := s.newOrgSvc.FindOrganization(ctx, filter)
|
|
if err != nil {
|
|
s.log.Error("error in new meta store", zap.Error(err))
|
|
} else if diff := cmp.Diff(o, n); diff != "" {
|
|
s.log.Error(fmt.Sprintf("unexpected read result -old/+new:\n\t%s", diff), zap.String("diff", diff), zap.String("call", "FindOrganization"))
|
|
}
|
|
return o, nil
|
|
}
|
|
|
|
func (s tenantService) FindOrganizations(ctx context.Context, filter influxdb.OrganizationFilter, opt ...influxdb.FindOptions) ([]*influxdb.Organization, int, error) {
|
|
o, no, err := s.oldOrgSvc.FindOrganizations(ctx, filter, opt...)
|
|
if err != nil {
|
|
return o, no, err
|
|
}
|
|
n, _, err := s.newOrgSvc.FindOrganizations(ctx, filter, opt...)
|
|
if err != nil {
|
|
s.log.Error("error in new meta store", zap.Error(err))
|
|
} else if diff := cmp.Diff(o, n); diff != "" {
|
|
s.log.Error(fmt.Sprintf("unexpected read result -old/+new:\n\t%s", diff), zap.String("diff", diff), zap.String("call", "FindOrganizations"))
|
|
}
|
|
return o, no, nil
|
|
}
|
|
|
|
func (s tenantService) CreateOrganization(ctx context.Context, b *influxdb.Organization) error {
|
|
return s.oldOrgSvc.CreateOrganization(ctx, b)
|
|
}
|
|
|
|
func (s tenantService) UpdateOrganization(ctx context.Context, id influxdb.ID, upd influxdb.OrganizationUpdate) (*influxdb.Organization, error) {
|
|
return s.oldOrgSvc.UpdateOrganization(ctx, id, upd)
|
|
}
|
|
|
|
func (s tenantService) DeleteOrganization(ctx context.Context, id influxdb.ID) error {
|
|
return s.oldOrgSvc.DeleteOrganization(ctx, id)
|
|
}
|
|
|
|
func (s tenantService) FindUserResourceMappings(ctx context.Context, filter influxdb.UserResourceMappingFilter, opt ...influxdb.FindOptions) ([]*influxdb.UserResourceMapping, int, error) {
|
|
o, no, err := s.oldURMSvc.FindUserResourceMappings(ctx, filter, opt...)
|
|
if err != nil {
|
|
return o, no, err
|
|
}
|
|
n, _, err := s.newURMSvc.FindUserResourceMappings(ctx, filter, opt...)
|
|
if err != nil {
|
|
s.log.Error("error in new meta store", zap.Error(err))
|
|
} else if diff := cmp.Diff(o, n); diff != "" {
|
|
s.log.Error(fmt.Sprintf("unexpected read result -old/+new:\n\t%s", diff), zap.String("diff", diff), zap.String("call", "FindUserResourceMappings"))
|
|
}
|
|
return o, no, nil
|
|
}
|
|
|
|
func (s tenantService) CreateUserResourceMapping(ctx context.Context, m *influxdb.UserResourceMapping) error {
|
|
return s.oldURMSvc.CreateUserResourceMapping(ctx, m)
|
|
}
|
|
|
|
func (s tenantService) DeleteUserResourceMapping(ctx context.Context, resourceID, userID influxdb.ID) error {
|
|
return s.oldURMSvc.DeleteUserResourceMapping(ctx, resourceID, userID)
|
|
}
|
|
|
|
func (s tenantService) FindUserByID(ctx context.Context, id influxdb.ID) (*influxdb.User, error) {
|
|
o, err := s.oldUserSvc.FindUserByID(ctx, id)
|
|
if err != nil {
|
|
return o, err
|
|
}
|
|
n, err := s.newUserSvc.FindUserByID(ctx, id)
|
|
if err != nil {
|
|
s.log.Error("error in new meta store", zap.Error(err))
|
|
} else if diff := cmp.Diff(o, n); diff != "" {
|
|
s.log.Error(fmt.Sprintf("unexpected read result -old/+new:\n\t%s", diff), zap.String("diff", diff), zap.String("call", "FindUserByID"))
|
|
}
|
|
return o, nil
|
|
}
|
|
|
|
func (s tenantService) FindUser(ctx context.Context, filter influxdb.UserFilter) (*influxdb.User, error) {
|
|
o, err := s.oldUserSvc.FindUser(ctx, filter)
|
|
if err != nil {
|
|
return o, err
|
|
}
|
|
n, err := s.newUserSvc.FindUser(ctx, filter)
|
|
if err != nil {
|
|
s.log.Error("error in new meta store", zap.Error(err))
|
|
} else if diff := cmp.Diff(o, n); diff != "" {
|
|
s.log.Error(fmt.Sprintf("unexpected read result -old/+new:\n\t%s", diff), zap.String("diff", diff), zap.String("call", "FindUser"))
|
|
}
|
|
return o, nil
|
|
}
|
|
|
|
func (s tenantService) FindUsers(ctx context.Context, filter influxdb.UserFilter, opt ...influxdb.FindOptions) ([]*influxdb.User, int, error) {
|
|
o, no, err := s.oldUserSvc.FindUsers(ctx, filter, opt...)
|
|
if err != nil {
|
|
return o, no, err
|
|
}
|
|
n, _, err := s.newUserSvc.FindUsers(ctx, filter, opt...)
|
|
if err != nil {
|
|
s.log.Error("error in new meta store", zap.Error(err))
|
|
} else if diff := cmp.Diff(o, n); diff != "" {
|
|
s.log.Error(fmt.Sprintf("unexpected read result -old/+new:\n\t%s", diff), zap.String("diff", diff), zap.String("call", "FindUsers"))
|
|
}
|
|
return o, no, nil
|
|
}
|
|
|
|
func (s tenantService) CreateUser(ctx context.Context, u *influxdb.User) error {
|
|
return s.oldUserSvc.CreateUser(ctx, u)
|
|
}
|
|
|
|
func (s tenantService) UpdateUser(ctx context.Context, id influxdb.ID, upd influxdb.UserUpdate) (*influxdb.User, error) {
|
|
return s.oldUserSvc.UpdateUser(ctx, id, upd)
|
|
}
|
|
|
|
func (s tenantService) DeleteUser(ctx context.Context, id influxdb.ID) error {
|
|
return s.oldUserSvc.DeleteUser(ctx, id)
|
|
}
|
|
|
|
func (s tenantService) SetPassword(ctx context.Context, userID influxdb.ID, password string) error {
|
|
return s.oldPwdSvc.SetPassword(ctx, userID, password)
|
|
}
|
|
|
|
func (s tenantService) ComparePassword(ctx context.Context, userID influxdb.ID, password string) error {
|
|
if err := s.oldPwdSvc.ComparePassword(ctx, userID, password); err != nil {
|
|
return err
|
|
}
|
|
err := s.newPwdSvc.ComparePassword(ctx, userID, password)
|
|
if err != nil {
|
|
s.log.Error("error in new meta store", zap.Error(err))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s tenantService) CompareAndSetPassword(ctx context.Context, userID influxdb.ID, old, new string) error {
|
|
return s.oldPwdSvc.CompareAndSetPassword(ctx, userID, old, new)
|
|
}
|