influxdb/tenant/service_org.go

234 lines
5.8 KiB
Go

package tenant
import (
"context"
"github.com/influxdata/influxdb/v2"
icontext "github.com/influxdata/influxdb/v2/context"
"github.com/influxdata/influxdb/v2/kit/platform"
"github.com/influxdata/influxdb/v2/kv"
)
type OrgSvc struct {
store *Store
svc *Service
}
func NewOrganizationSvc(st *Store, svc *Service) *OrgSvc {
return &OrgSvc{
store: st,
svc: svc,
}
}
// Returns a single organization by ID.
func (s *OrgSvc) FindOrganizationByID(ctx context.Context, id platform.ID) (*influxdb.Organization, error) {
var org *influxdb.Organization
err := s.store.View(ctx, func(tx kv.Tx) error {
o, err := s.store.GetOrg(ctx, tx, id)
if err != nil {
return err
}
org = o
return nil
})
if err != nil {
return nil, err
}
return org, nil
}
// Returns the first organization that matches filter.
func (s *OrgSvc) FindOrganization(ctx context.Context, filter influxdb.OrganizationFilter) (*influxdb.Organization, error) {
if filter.ID != nil {
return s.FindOrganizationByID(ctx, *filter.ID)
}
if filter.Name == nil {
return nil, influxdb.ErrInvalidOrgFilter
}
var org *influxdb.Organization
err := s.store.View(ctx, func(tx kv.Tx) error {
o, err := s.store.GetOrgByName(ctx, tx, *filter.Name)
if err != nil {
return err
}
org = o
return nil
})
if err != nil {
return nil, err
}
return org, nil
}
// Returns a list of organizations that match filter and the total count of matching organizations.
// Additional options provide pagination & sorting.
func (s *OrgSvc) FindOrganizations(ctx context.Context, filter influxdb.OrganizationFilter, opt ...influxdb.FindOptions) ([]*influxdb.Organization, int, error) {
// if im given a id or a name I know I can only return 1
if filter.ID != nil || filter.Name != nil {
org, err := s.FindOrganization(ctx, filter)
if err != nil {
return nil, 0, err
}
return []*influxdb.Organization{org}, 1, nil
}
var orgs []*influxdb.Organization
if filter.UserID != nil {
// find urms for orgs with this user
urms, _, err := s.svc.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{
UserID: *filter.UserID,
ResourceType: influxdb.OrgsResourceType,
}, opt...)
if err != nil {
return nil, 0, err
}
// find orgs by the urm's resource ids.
for _, urm := range urms {
o, err := s.FindOrganizationByID(ctx, urm.ResourceID)
if err == nil {
// if there is an error then this is a crufty urm and we should just move on
orgs = append(orgs, o)
}
}
return orgs, len(orgs), nil
}
err := s.store.View(ctx, func(tx kv.Tx) error {
os, err := s.store.ListOrgs(ctx, tx, opt...)
if err != nil {
return err
}
orgs = os
return nil
})
if err != nil {
return nil, 0, err
}
return orgs, len(orgs), err
}
// Creates a new organization and sets b.ID with the new identifier.
func (s *OrgSvc) CreateOrganization(ctx context.Context, o *influxdb.Organization) error {
err := s.store.Update(ctx, func(tx kv.Tx) error {
return s.store.CreateOrg(ctx, tx, o)
})
if err != nil {
return err
}
tb := &influxdb.Bucket{
OrgID: o.ID,
Type: influxdb.BucketTypeSystem,
Name: influxdb.TasksSystemBucketName,
RetentionPeriod: influxdb.TasksSystemBucketRetention,
Description: "System bucket for task logs",
}
if err := s.svc.CreateBucket(ctx, tb); err != nil {
return err
}
mb := &influxdb.Bucket{
OrgID: o.ID,
Type: influxdb.BucketTypeSystem,
Name: influxdb.MonitoringSystemBucketName,
RetentionPeriod: influxdb.MonitoringSystemBucketRetention,
Description: "System bucket for monitoring logs",
}
if err := s.svc.CreateBucket(ctx, mb); err != nil {
return err
}
// create associated URM
userID, err := icontext.GetUserID(ctx)
if err == nil && userID.Valid() {
// if I am given a userid i can associate the user as the org owner
err = s.svc.CreateUserResourceMapping(ctx, &influxdb.UserResourceMapping{
UserID: userID,
UserType: influxdb.Owner,
MappingType: influxdb.UserMappingType,
ResourceType: influxdb.OrgsResourceType,
ResourceID: o.ID,
})
if err != nil {
return err
}
}
return nil
}
// Updates a single organization with changeset.
// Returns the new organization state after update.
func (s *OrgSvc) UpdateOrganization(ctx context.Context, id platform.ID, upd influxdb.OrganizationUpdate) (*influxdb.Organization, error) {
var org *influxdb.Organization
err := s.store.Update(ctx, func(tx kv.Tx) error {
o, err := s.store.UpdateOrg(ctx, tx, id, upd)
if err != nil {
return err
}
org = o
return nil
})
if err != nil {
return nil, err
}
return org, nil
}
// DeleteOrganization removes a organization by ID and its dependent resources.
func (s *OrgSvc) DeleteOrganization(ctx context.Context, id platform.ID) error {
// clean up the buckets for this organization
filter := influxdb.BucketFilter{
OrganizationID: &id,
}
bs, _, err := s.svc.FindBuckets(ctx, filter)
if err != nil {
return err
}
for _, b := range bs {
if err := s.svc.DeleteBucket(internalCtx(ctx), b.ID); err != nil {
if err != ErrBucketNotFound {
return err
}
}
}
err = s.store.Update(ctx, func(tx kv.Tx) error {
return s.store.DeleteOrg(ctx, tx, id)
})
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.
func (s *OrgSvc) removeResourceRelations(ctx context.Context, resourceID platform.ID) error {
urms, _, err := s.svc.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{
ResourceID: resourceID,
})
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
}