2020-03-17 19:23:00 +00:00
package tenant
import (
"context"
2020-08-11 14:56:42 +00:00
"fmt"
"strings"
2020-03-17 19:23:00 +00:00
2021-09-13 19:12:35 +00:00
"github.com/influxdata/influxdb/v2"
2021-03-30 18:10:02 +00:00
"github.com/influxdata/influxdb/v2/kit/platform"
"github.com/influxdata/influxdb/v2/kit/platform/errors"
2020-04-03 17:39:20 +00:00
"github.com/influxdata/influxdb/v2/kv"
2020-03-17 19:23:00 +00:00
)
2020-07-30 21:55:25 +00:00
type BucketSvc struct {
store * Store
svc * Service
}
func NewBucketSvc ( st * Store , svc * Service ) * BucketSvc {
return & BucketSvc {
store : st ,
svc : svc ,
}
}
2020-03-17 19:23:00 +00:00
// FindBucketByID returns a single bucket by ID.
2021-03-30 18:10:02 +00:00
func ( s * BucketSvc ) FindBucketByID ( ctx context . Context , id platform . ID ) ( * influxdb . Bucket , error ) {
2020-03-17 19:23:00 +00:00
var bucket * influxdb . Bucket
err := s . store . View ( ctx , func ( tx kv . Tx ) error {
b , err := s . store . GetBucket ( ctx , tx , id )
if err != nil {
return err
}
bucket = b
return nil
} )
if err != nil {
return nil , err
}
return bucket , nil
}
2021-03-30 18:10:02 +00:00
func ( s * BucketSvc ) FindBucketByName ( ctx context . Context , orgID platform . ID , name string ) ( * influxdb . Bucket , error ) {
2020-03-17 19:23:00 +00:00
var bucket * influxdb . Bucket
err := s . store . View ( ctx , func ( tx kv . Tx ) error {
b , err := s . store . GetBucketByName ( ctx , tx , orgID , name )
if err != nil {
return err
}
bucket = b
return nil
} )
if err != nil {
return nil , err
}
return bucket , nil
}
// FindBucket returns the first bucket that matches filter.
2020-07-30 21:55:25 +00:00
func ( s * BucketSvc ) FindBucket ( ctx context . Context , filter influxdb . BucketFilter ) ( * influxdb . Bucket , error ) {
2020-05-12 22:00:38 +00:00
if filter . ID != nil {
return s . FindBucketByID ( ctx , * filter . ID )
}
if filter . Name != nil && filter . OrganizationID != nil {
return s . FindBucketByName ( ctx , * filter . OrganizationID , * filter . Name )
}
2020-03-17 19:23:00 +00:00
buckets , _ , err := s . FindBuckets ( ctx , filter , influxdb . FindOptions {
Limit : 1 ,
} )
if err != nil {
return nil , err
}
2020-04-23 14:32:50 +00:00
if len ( buckets ) < 1 {
return nil , ErrBucketNotFound
2020-03-17 19:23:00 +00:00
}
return buckets [ 0 ] , nil
}
// FindBuckets returns a list of buckets that match filter and the total count of matching buckets.
// Additional options provide pagination & sorting.
2020-07-30 21:55:25 +00:00
func ( s * BucketSvc ) FindBuckets ( ctx context . Context , filter influxdb . BucketFilter , opt ... influxdb . FindOptions ) ( [ ] * influxdb . Bucket , int , error ) {
2020-03-17 19:23:00 +00:00
if filter . ID != nil {
b , err := s . FindBucketByID ( ctx , * filter . ID )
if err != nil {
return nil , 0 , err
}
return [ ] * influxdb . Bucket { b } , 1 , nil
}
2020-07-30 21:55:25 +00:00
if filter . OrganizationID == nil && filter . Org != nil {
org , err := s . svc . FindOrganization ( ctx , influxdb . OrganizationFilter { Name : filter . Org } )
if err != nil {
return nil , 0 , err
}
filter . OrganizationID = & org . ID
}
2020-03-17 19:23:00 +00:00
var buckets [ ] * influxdb . Bucket
err := s . store . View ( ctx , func ( tx kv . Tx ) error {
2020-05-22 15:30:14 +00:00
if filter . Name != nil && filter . OrganizationID != nil {
b , err := s . store . GetBucketByName ( ctx , tx , * filter . OrganizationID , * filter . Name )
if err != nil {
return err
}
buckets = [ ] * influxdb . Bucket { b }
return nil
}
2020-03-17 19:23:00 +00:00
bs , err := s . store . ListBuckets ( ctx , tx , BucketFilter {
Name : filter . Name ,
OrganizationID : filter . OrganizationID ,
} , opt ... )
if err != nil {
return err
}
buckets = bs
return nil
} )
if err != nil {
return nil , 0 , err
}
return buckets , len ( buckets ) , nil
}
// CreateBucket creates a new bucket and sets b.ID with the new identifier.
2020-07-30 21:55:25 +00:00
func ( s * BucketSvc ) CreateBucket ( ctx context . Context , b * influxdb . Bucket ) error {
2020-03-17 19:23:00 +00:00
if ! b . OrgID . Valid ( ) {
// we need a valid org id
return ErrOrgNotFound
}
2020-08-11 14:56:42 +00:00
if err := validBucketName ( b . Name , b . Type ) ; err != nil {
return err
}
2020-07-30 21:55:25 +00:00
// make sure the org exists
if _ , err := s . svc . FindOrganizationByID ( ctx , b . OrgID ) ; err != nil {
return err
}
2020-03-17 19:23:00 +00:00
2020-07-30 21:55:25 +00:00
return s . store . Update ( ctx , func ( tx kv . Tx ) error {
2020-04-06 21:58:15 +00:00
return s . store . CreateBucket ( ctx , tx , b )
2020-03-17 19:23:00 +00:00
} )
}
// UpdateBucket updates a single bucket with changeset.
// Returns the new bucket state after update.
2021-03-30 18:10:02 +00:00
func ( s * BucketSvc ) UpdateBucket ( ctx context . Context , id platform . ID , upd influxdb . BucketUpdate ) ( * influxdb . Bucket , error ) {
2020-03-17 19:23:00 +00:00
var bucket * influxdb . Bucket
err := s . store . Update ( ctx , func ( tx kv . Tx ) error {
b , err := s . store . UpdateBucket ( ctx , tx , id , upd )
if err != nil {
return err
}
bucket = b
return nil
} )
if err != nil {
return nil , err
}
return bucket , nil
}
// DeleteBucket removes a bucket by ID.
2021-03-30 18:10:02 +00:00
func ( s * BucketSvc ) DeleteBucket ( ctx context . Context , id platform . ID ) error {
2020-07-30 21:55:25 +00:00
err := s . store . Update ( ctx , func ( tx kv . Tx ) error {
2020-03-17 19:23:00 +00:00
bucket , err := s . store . GetBucket ( ctx , tx , id )
if err != nil {
return err
}
2020-07-30 21:55:25 +00:00
if bucket . Type == influxdb . BucketTypeSystem && ! isInternal ( ctx ) {
2020-03-17 19:23:00 +00:00
// TODO: I think we should allow bucket deletes but maybe im wrong.
return errDeleteSystemBucket
}
if err := s . store . DeleteBucket ( ctx , tx , id ) ; err != nil {
return err
}
2020-07-30 21:55:25 +00:00
return nil
} )
if err != nil {
return err
}
return s . removeResourceRelations ( ctx , id )
}
// removeResourceRelations allows us to clean up any resource relationship that would have normally been left over after a delete action of a resource.
2021-03-30 18:10:02 +00:00
func ( s * BucketSvc ) removeResourceRelations ( ctx context . Context , resourceID platform . ID ) error {
2020-07-30 21:55:25 +00:00
urms , _ , err := s . svc . FindUserResourceMappings ( ctx , influxdb . UserResourceMappingFilter {
ResourceID : resourceID ,
2020-03-17 19:23:00 +00:00
} )
2020-07-30 21:55:25 +00:00
if err != nil {
return err
}
for _ , urm := range urms {
err := s . svc . DeleteUserResourceMapping ( ctx , urm . ResourceID , urm . UserID )
if err != nil && err != ErrURMNotFound {
return err
}
}
return nil
2020-03-17 19:23:00 +00:00
}
2020-08-11 14:56:42 +00:00
// validBucketName reports any errors with bucket names
func validBucketName ( name string , typ influxdb . BucketType ) error {
// names starting with an underscore are reserved for system buckets
if strings . HasPrefix ( name , "_" ) && typ != influxdb . BucketTypeSystem {
2021-03-30 18:10:02 +00:00
return & errors . Error {
Code : errors . EInvalid ,
2020-08-11 14:56:42 +00:00
Msg : fmt . Sprintf ( "bucket name %s is invalid. Buckets may not start with underscore" , name ) ,
Op : influxdb . OpCreateBucket ,
}
}
// quotation marks will cause queries to fail
if strings . Contains ( name , "\"" ) {
2021-03-30 18:10:02 +00:00
return & errors . Error {
Code : errors . EInvalid ,
2020-08-11 14:56:42 +00:00
Msg : fmt . Sprintf ( "bucket name %s is invalid. Bucket names may not include quotation marks" , name ) ,
Op : influxdb . OpCreateBucket ,
}
}
return nil
}