213 lines
4.5 KiB
Go
213 lines
4.5 KiB
Go
package label
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
|
|
"github.com/influxdata/influxdb/v2"
|
|
"github.com/influxdata/influxdb/v2/kv"
|
|
)
|
|
|
|
type Service struct {
|
|
store *Store
|
|
}
|
|
|
|
func NewService(st *Store) influxdb.LabelService {
|
|
return &Service{
|
|
store: st,
|
|
}
|
|
}
|
|
|
|
// CreateLabel creates a new label.
|
|
func (s *Service) CreateLabel(ctx context.Context, l *influxdb.Label) error {
|
|
if err := l.Validate(); err != nil {
|
|
return &influxdb.Error{
|
|
Code: influxdb.EInvalid,
|
|
Err: err,
|
|
}
|
|
}
|
|
|
|
l.Name = strings.TrimSpace(l.Name)
|
|
|
|
err := s.store.Update(ctx, func(tx kv.Tx) error {
|
|
if err := uniqueLabelName(ctx, tx, l); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := s.store.CreateLabel(ctx, tx, l); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
// FindLabelByID finds a label by its ID
|
|
func (s *Service) FindLabelByID(ctx context.Context, id influxdb.ID) (*influxdb.Label, error) {
|
|
var l *influxdb.Label
|
|
|
|
err := s.store.View(ctx, func(tx kv.Tx) error {
|
|
label, e := s.store.GetLabel(ctx, tx, id)
|
|
if e != nil {
|
|
return e
|
|
}
|
|
l = label
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, &influxdb.Error{
|
|
Err: err,
|
|
}
|
|
}
|
|
|
|
return l, nil
|
|
}
|
|
|
|
// FindLabels returns a list of labels that match a filter.
|
|
func (s *Service) FindLabels(ctx context.Context, filter influxdb.LabelFilter, opt ...influxdb.FindOptions) ([]*influxdb.Label, error) {
|
|
ls := []*influxdb.Label{}
|
|
err := s.store.View(ctx, func(tx kv.Tx) error {
|
|
labels, err := s.store.ListLabels(ctx, tx, filter)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ls = labels
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return ls, nil
|
|
}
|
|
|
|
func (s *Service) FindResourceLabels(ctx context.Context, filter influxdb.LabelMappingFilter) ([]*influxdb.Label, error) {
|
|
ls := []*influxdb.Label{}
|
|
if err := s.store.View(ctx, func(tx kv.Tx) error {
|
|
return s.store.FindResourceLabels(ctx, tx, filter, &ls)
|
|
}); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return ls, nil
|
|
}
|
|
|
|
// UpdateLabel updates a label.
|
|
func (s *Service) UpdateLabel(ctx context.Context, id influxdb.ID, upd influxdb.LabelUpdate) (*influxdb.Label, error) {
|
|
var label *influxdb.Label
|
|
err := s.store.Update(ctx, func(tx kv.Tx) error {
|
|
l, e := s.store.UpdateLabel(ctx, tx, id, upd)
|
|
if e != nil {
|
|
return &influxdb.Error{
|
|
Err: e,
|
|
}
|
|
}
|
|
label = l
|
|
return nil
|
|
})
|
|
|
|
return label, err
|
|
}
|
|
|
|
// DeleteLabel deletes a label.
|
|
func (s *Service) DeleteLabel(ctx context.Context, id influxdb.ID) error {
|
|
err := s.store.Update(ctx, func(tx kv.Tx) error {
|
|
return s.store.DeleteLabel(ctx, tx, id)
|
|
})
|
|
if err != nil {
|
|
return &influxdb.Error{
|
|
Err: err,
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
//******* Label Mappings *******//
|
|
|
|
// CreateLabelMapping creates a new mapping between a resource and a label.
|
|
func (s *Service) CreateLabelMapping(ctx context.Context, m *influxdb.LabelMapping) error {
|
|
err := s.store.View(ctx, func(tx kv.Tx) error {
|
|
if _, err := s.store.GetLabel(ctx, tx, m.LabelID); err != nil {
|
|
return err
|
|
}
|
|
|
|
ls := []*influxdb.Label{}
|
|
err := s.store.FindResourceLabels(ctx, tx, influxdb.LabelMappingFilter{ResourceID: m.ResourceID, ResourceType: m.ResourceType}, &ls)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for i := 0; i < len(ls); i++ {
|
|
if ls[i].ID == m.LabelID {
|
|
return influxdb.ErrLabelExistsOnResource
|
|
}
|
|
}
|
|
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return s.store.Update(ctx, func(tx kv.Tx) error {
|
|
return s.store.CreateLabelMapping(ctx, tx, m)
|
|
})
|
|
}
|
|
|
|
// DeleteLabelMapping deletes a label mapping.
|
|
func (s *Service) DeleteLabelMapping(ctx context.Context, m *influxdb.LabelMapping) error {
|
|
err := s.store.Update(ctx, func(tx kv.Tx) error {
|
|
return s.store.DeleteLabelMapping(ctx, tx, m)
|
|
})
|
|
if err != nil {
|
|
return &influxdb.Error{
|
|
Err: err,
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
//******* helper functions *******//
|
|
|
|
func unique(ctx context.Context, tx kv.Tx, indexBucket, indexKey []byte) error {
|
|
bucket, err := tx.Bucket(indexBucket)
|
|
if err != nil {
|
|
return kv.UnexpectedIndexError(err)
|
|
}
|
|
|
|
_, err = bucket.Get(indexKey)
|
|
// if not found then this is _unique_.
|
|
if kv.IsNotFound(err) {
|
|
return nil
|
|
}
|
|
|
|
// no error means this is not unique
|
|
if err == nil {
|
|
return kv.NotUniqueError
|
|
}
|
|
|
|
// any other error is some sort of internal server error
|
|
return kv.UnexpectedIndexError(err)
|
|
}
|
|
|
|
func uniqueLabelName(ctx context.Context, tx kv.Tx, lbl *influxdb.Label) error {
|
|
key, err := labelIndexKey(lbl)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// labels are unique by `organization:label_name`
|
|
err = unique(ctx, tx, labelIndex, key)
|
|
if err == kv.NotUniqueError {
|
|
return labelAlreadyExistsError(lbl)
|
|
}
|
|
return err
|
|
}
|