Merge pull request #12734 from influxdata/scope-labels

Scope labels to organizations
pull/12747/head
Jade McGough 2019-03-19 11:37:44 -07:00 committed by GitHub
commit b49bf9ed09
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 300 additions and 127 deletions

View File

@ -21,16 +21,8 @@ func NewLabelService(s influxdb.LabelService) *LabelService {
}
}
func newLabelPermission(a influxdb.Action, id influxdb.ID) (*influxdb.Permission, error) {
p := &influxdb.Permission{
Action: a,
Resource: influxdb.Resource{
Type: influxdb.LabelsResourceType,
ID: &id,
},
}
return p, p.Valid()
func newLabelPermission(a influxdb.Action, orgID, id influxdb.ID) (*influxdb.Permission, error) {
return influxdb.NewPermissionAtID(id, a, influxdb.LabelsResourceType, orgID)
}
func newResourcePermission(a influxdb.Action, id influxdb.ID, resourceType influxdb.ResourceType) (*influxdb.Permission, error) {
@ -62,8 +54,8 @@ func authorizeLabelMappingAction(ctx context.Context, action influxdb.Action, id
return nil
}
func authorizeReadLabel(ctx context.Context, id influxdb.ID) error {
p, err := newLabelPermission(influxdb.ReadAction, id)
func authorizeReadLabel(ctx context.Context, orgID, id influxdb.ID) error {
p, err := newLabelPermission(influxdb.ReadAction, orgID, id)
if err != nil {
return err
}
@ -75,8 +67,8 @@ func authorizeReadLabel(ctx context.Context, id influxdb.ID) error {
return nil
}
func authorizeWriteLabel(ctx context.Context, id influxdb.ID) error {
p, err := newLabelPermission(influxdb.WriteAction, id)
func authorizeWriteLabel(ctx context.Context, orgID, id influxdb.ID) error {
p, err := newLabelPermission(influxdb.WriteAction, orgID, id)
if err != nil {
return err
}
@ -90,12 +82,12 @@ func authorizeWriteLabel(ctx context.Context, id influxdb.ID) error {
// FindLabelByID checks to see if the authorizer on context has read access to the label id provided.
func (s *LabelService) FindLabelByID(ctx context.Context, id influxdb.ID) (*influxdb.Label, error) {
if err := authorizeReadLabel(ctx, id); err != nil {
l, err := s.s.FindLabelByID(ctx, id)
if err != nil {
return nil, err
}
l, err := s.s.FindLabelByID(ctx, id)
if err != nil {
if err := authorizeReadLabel(ctx, l.OrganizationID, id); err != nil {
return nil, err
}
@ -115,7 +107,7 @@ func (s *LabelService) FindLabels(ctx context.Context, filter influxdb.LabelFilt
// https://github.com/golang/go/wiki/SliceTricks#filtering-without-allocating
labels := ls[:0]
for _, l := range ls {
err := authorizeReadLabel(ctx, l.ID)
err := authorizeReadLabel(ctx, l.OrganizationID, l.ID)
if err != nil && influxdb.ErrorCode(err) != influxdb.EUnauthorized {
return nil, err
}
@ -144,7 +136,7 @@ func (s *LabelService) FindResourceLabels(ctx context.Context, filter influxdb.L
labels := ls[:0]
for _, l := range ls {
err := authorizeReadLabel(ctx, l.ID)
err := authorizeReadLabel(ctx, l.OrganizationID, l.ID)
if err != nil && influxdb.ErrorCode(err) != influxdb.EUnauthorized {
return nil, err
}
@ -159,14 +151,9 @@ func (s *LabelService) FindResourceLabels(ctx context.Context, filter influxdb.L
return labels, nil
}
// CreateLabel checks to see if the authorizer on context has write access to the global labels resource.
// CreateLabel checks to see if the authorizer on context has read access to the new label's org.
func (s *LabelService) CreateLabel(ctx context.Context, l *influxdb.Label) error {
p, err := influxdb.NewGlobalPermission(influxdb.WriteAction, influxdb.LabelsResourceType)
if err != nil {
return err
}
if err := IsAllowed(ctx, *p); err != nil {
if err := authorizeReadOrg(ctx, l.OrganizationID); err != nil {
return err
}
@ -175,7 +162,12 @@ func (s *LabelService) CreateLabel(ctx context.Context, l *influxdb.Label) error
// CreateLabelMapping checks to see if the authorizer on context has write access to the label and the resource contained by the label mapping in creation.
func (s *LabelService) CreateLabelMapping(ctx context.Context, m *influxdb.LabelMapping) error {
if err := authorizeWriteLabel(ctx, m.LabelID); err != nil {
l, err := s.s.FindLabelByID(ctx, m.LabelID)
if err != nil {
return err
}
if err := authorizeWriteLabel(ctx, l.OrganizationID, m.LabelID); err != nil {
return err
}
@ -188,12 +180,12 @@ func (s *LabelService) CreateLabelMapping(ctx context.Context, m *influxdb.Label
// UpdateLabel checks to see if the authorizer on context has write access to the label provided.
func (s *LabelService) UpdateLabel(ctx context.Context, id influxdb.ID, upd influxdb.LabelUpdate) (*influxdb.Label, error) {
_, err := s.s.FindLabelByID(ctx, id)
l, err := s.s.FindLabelByID(ctx, id)
if err != nil {
return nil, err
}
if err := authorizeWriteLabel(ctx, id); err != nil {
if err := authorizeWriteLabel(ctx, l.OrganizationID, id); err != nil {
return nil, err
}
@ -202,12 +194,12 @@ func (s *LabelService) UpdateLabel(ctx context.Context, id influxdb.ID, upd infl
// DeleteLabel checks to see if the authorizer on context has write access to the label provided.
func (s *LabelService) DeleteLabel(ctx context.Context, id influxdb.ID) error {
_, err := s.s.FindLabelByID(ctx, id)
l, err := s.s.FindLabelByID(ctx, id)
if err != nil {
return err
}
if err := authorizeWriteLabel(ctx, id); err != nil {
if err := authorizeWriteLabel(ctx, l.OrganizationID, id); err != nil {
return err
}
@ -216,12 +208,12 @@ func (s *LabelService) DeleteLabel(ctx context.Context, id influxdb.ID) error {
// DeleteLabelMapping checks to see if the authorizer on context has write access to the label and the resource of the label mapping to delete.
func (s *LabelService) DeleteLabelMapping(ctx context.Context, m *influxdb.LabelMapping) error {
_, err := s.s.FindLabelByID(ctx, m.LabelID)
l, err := s.s.FindLabelByID(ctx, m.LabelID)
if err != nil {
return err
}
if err := authorizeWriteLabel(ctx, m.LabelID); err != nil {
if err := authorizeWriteLabel(ctx, l.OrganizationID, m.LabelID); err != nil {
return err
}

View File

@ -14,6 +14,10 @@ import (
influxdbtesting "github.com/influxdata/influxdb/testing"
)
const (
orgOneID = "020f755c3c083000"
)
var labelCmpOptions = cmp.Options{
cmp.Comparer(func(x, y []byte) bool {
return bytes.Equal(x, y)
@ -51,7 +55,8 @@ func TestLabelService_FindLabelByID(t *testing.T) {
LabelService: &mock.LabelService{
FindLabelByIDFn: func(ctx context.Context, id influxdb.ID) (*influxdb.Label, error) {
return &influxdb.Label{
ID: id,
ID: id,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
}, nil
},
},
@ -76,7 +81,8 @@ func TestLabelService_FindLabelByID(t *testing.T) {
LabelService: &mock.LabelService{
FindLabelByIDFn: func(ctx context.Context, id influxdb.ID) (*influxdb.Label, error) {
return &influxdb.Label{
ID: id,
ID: id,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
}, nil
},
},
@ -93,7 +99,7 @@ func TestLabelService_FindLabelByID(t *testing.T) {
},
wants: wants{
err: &influxdb.Error{
Msg: "read:labels/0000000000000001 is unauthorized",
Msg: "read:orgs/020f755c3c083000/labels/0000000000000001 is unauthorized",
Code: influxdb.EUnauthorized,
},
},
@ -138,13 +144,16 @@ func TestLabelService_FindLabels(t *testing.T) {
FindLabelsFn: func(ctx context.Context, filter influxdb.LabelFilter) ([]*influxdb.Label, error) {
return []*influxdb.Label{
{
ID: 1,
ID: 1,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
},
{
ID: 2,
ID: 2,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
},
{
ID: 3,
ID: 3,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
},
}, nil
},
@ -161,13 +170,16 @@ func TestLabelService_FindLabels(t *testing.T) {
wants: wants{
labels: []*influxdb.Label{
{
ID: 1,
ID: 1,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
},
{
ID: 2,
ID: 2,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
},
{
ID: 3,
ID: 3,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
},
},
},
@ -179,13 +191,16 @@ func TestLabelService_FindLabels(t *testing.T) {
FindLabelsFn: func(ctx context.Context, filter influxdb.LabelFilter) ([]*influxdb.Label, error) {
return []*influxdb.Label{
{
ID: 1,
ID: 1,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
},
{
ID: 2,
ID: 2,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
},
{
ID: 3,
ID: 3,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
},
}, nil
},
@ -203,7 +218,8 @@ func TestLabelService_FindLabels(t *testing.T) {
wants: wants{
labels: []*influxdb.Label{
{
ID: 1,
ID: 1,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
},
},
},
@ -215,13 +231,16 @@ func TestLabelService_FindLabels(t *testing.T) {
FindLabelsFn: func(ctx context.Context, filter influxdb.LabelFilter) ([]*influxdb.Label, error) {
return []*influxdb.Label{
{
ID: 1,
ID: 1,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
},
{
ID: 2,
ID: 2,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
},
{
ID: 3,
ID: 3,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
},
}, nil
},
@ -283,12 +302,14 @@ func TestLabelService_UpdateLabel(t *testing.T) {
LabelService: &mock.LabelService{
FindLabelByIDFn: func(ctc context.Context, id influxdb.ID) (*influxdb.Label, error) {
return &influxdb.Label{
ID: 1,
ID: 1,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
}, nil
},
UpdateLabelFn: func(ctx context.Context, id influxdb.ID, upd influxdb.LabelUpdate) (*influxdb.Label, error) {
return &influxdb.Label{
ID: 1,
ID: 1,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
}, nil
},
},
@ -315,12 +336,14 @@ func TestLabelService_UpdateLabel(t *testing.T) {
LabelService: &mock.LabelService{
FindLabelByIDFn: func(ctc context.Context, id influxdb.ID) (*influxdb.Label, error) {
return &influxdb.Label{
ID: 1,
ID: 1,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
}, nil
},
UpdateLabelFn: func(ctx context.Context, id influxdb.ID, upd influxdb.LabelUpdate) (*influxdb.Label, error) {
return &influxdb.Label{
ID: 1,
ID: 1,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
}, nil
},
},
@ -339,7 +362,7 @@ func TestLabelService_UpdateLabel(t *testing.T) {
},
wants: wants{
err: &influxdb.Error{
Msg: "write:labels/0000000000000001 is unauthorized",
Msg: "write:orgs/020f755c3c083000/labels/0000000000000001 is unauthorized",
Code: influxdb.EUnauthorized,
},
},
@ -383,7 +406,8 @@ func TestLabelService_DeleteLabel(t *testing.T) {
LabelService: &mock.LabelService{
FindLabelByIDFn: func(ctc context.Context, id influxdb.ID) (*influxdb.Label, error) {
return &influxdb.Label{
ID: 1,
ID: 1,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
}, nil
},
DeleteLabelFn: func(ctx context.Context, id influxdb.ID) error {
@ -397,8 +421,9 @@ func TestLabelService_DeleteLabel(t *testing.T) {
{
Action: "write",
Resource: influxdb.Resource{
Type: influxdb.LabelsResourceType,
ID: influxdbtesting.IDPtr(1),
Type: influxdb.LabelsResourceType,
ID: influxdbtesting.IDPtr(1),
OrgID: influxdbtesting.IDPtr(influxdbtesting.MustIDBase16(orgOneID)),
},
},
},
@ -413,7 +438,8 @@ func TestLabelService_DeleteLabel(t *testing.T) {
LabelService: &mock.LabelService{
FindLabelByIDFn: func(ctc context.Context, id influxdb.ID) (*influxdb.Label, error) {
return &influxdb.Label{
ID: 1,
ID: 1,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
}, nil
},
DeleteLabelFn: func(ctx context.Context, id influxdb.ID) error {
@ -427,15 +453,16 @@ func TestLabelService_DeleteLabel(t *testing.T) {
{
Action: "read",
Resource: influxdb.Resource{
Type: influxdb.LabelsResourceType,
ID: influxdbtesting.IDPtr(1),
Type: influxdb.LabelsResourceType,
ID: influxdbtesting.IDPtr(1),
OrgID: influxdbtesting.IDPtr(influxdbtesting.MustIDBase16(orgOneID)),
},
},
},
},
wants: wants{
err: &influxdb.Error{
Msg: "write:labels/0000000000000001 is unauthorized",
Msg: "write:orgs/020f755c3c083000/labels/0000000000000001 is unauthorized",
Code: influxdb.EUnauthorized,
},
},
@ -483,9 +510,10 @@ func TestLabelService_CreateLabel(t *testing.T) {
},
args: args{
permission: influxdb.Permission{
Action: "write",
Action: "read",
Resource: influxdb.Resource{
Type: influxdb.LabelsResourceType,
ID: influxdbtesting.IDPtr(influxdbtesting.MustIDBase16(orgOneID)),
Type: influxdb.OrgsResourceType,
},
},
},
@ -512,7 +540,7 @@ func TestLabelService_CreateLabel(t *testing.T) {
},
wants: wants{
err: &influxdb.Error{
Msg: "write:labels is unauthorized",
Msg: "read:orgs/020f755c3c083000 is unauthorized",
Code: influxdb.EUnauthorized,
},
},
@ -526,7 +554,7 @@ func TestLabelService_CreateLabel(t *testing.T) {
ctx := context.Background()
ctx = influxdbcontext.SetAuthorizer(ctx, &Authorizer{[]influxdb.Permission{tt.args.permission}})
err := s.CreateLabel(ctx, &influxdb.Label{Name: "name"})
err := s.CreateLabel(ctx, &influxdb.Label{Name: "name", OrganizationID: influxdbtesting.MustIDBase16(orgOneID)})
influxdbtesting.ErrorsEqual(t, err, tt.wants.err)
})
}
@ -557,13 +585,16 @@ func TestLabelService_FindResourceLabels(t *testing.T) {
FindResourceLabelsFn: func(ctx context.Context, f influxdb.LabelMappingFilter) ([]*influxdb.Label, error) {
return []*influxdb.Label{
{
ID: 1,
ID: 1,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
},
{
ID: 2,
ID: 2,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
},
{
ID: 3,
ID: 3,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
},
}, nil
},
@ -594,13 +625,16 @@ func TestLabelService_FindResourceLabels(t *testing.T) {
err: nil,
labels: []*influxdb.Label{
{
ID: 1,
ID: 1,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
},
{
ID: 2,
ID: 2,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
},
{
ID: 3,
ID: 3,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
},
},
},
@ -612,13 +646,16 @@ func TestLabelService_FindResourceLabels(t *testing.T) {
FindResourceLabelsFn: func(ctx context.Context, f influxdb.LabelMappingFilter) ([]*influxdb.Label, error) {
return []*influxdb.Label{
{
ID: 1,
ID: 1,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
},
{
ID: 2,
ID: 2,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
},
{
ID: 3,
ID: 3,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
},
}, nil
},
@ -650,7 +687,8 @@ func TestLabelService_FindResourceLabels(t *testing.T) {
err: nil,
labels: []*influxdb.Label{
{
ID: 3,
ID: 3,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
},
},
},
@ -662,13 +700,16 @@ func TestLabelService_FindResourceLabels(t *testing.T) {
FindResourceLabelsFn: func(ctx context.Context, f influxdb.LabelMappingFilter) ([]*influxdb.Label, error) {
return []*influxdb.Label{
{
ID: 1,
ID: 1,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
},
{
ID: 2,
ID: 2,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
},
{
ID: 3,
ID: 3,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
},
}, nil
},
@ -700,13 +741,16 @@ func TestLabelService_FindResourceLabels(t *testing.T) {
FindResourceLabelsFn: func(ctx context.Context, f influxdb.LabelMappingFilter) ([]*influxdb.Label, error) {
return []*influxdb.Label{
{
ID: 1,
ID: 1,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
},
{
ID: 2,
ID: 2,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
},
{
ID: 3,
ID: 3,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
},
}, nil
},
@ -774,6 +818,12 @@ func TestLabelService_CreateLabelMapping(t *testing.T) {
name: "authorized to create label mapping",
fields: fields{
LabelService: &mock.LabelService{
FindLabelByIDFn: func(ctx context.Context, id influxdb.ID) (*influxdb.Label, error) {
return &influxdb.Label{
ID: 1,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
}, nil
},
CreateLabelMappingFn: func(ctx context.Context, lm *influxdb.LabelMapping) error {
return nil
},
@ -809,6 +859,12 @@ func TestLabelService_CreateLabelMapping(t *testing.T) {
name: "unauthorized to create label mapping for resources on which the user does not have write access",
fields: fields{
LabelService: &mock.LabelService{
FindLabelByIDFn: func(ctx context.Context, id influxdb.ID) (*influxdb.Label, error) {
return &influxdb.Label{
ID: 1,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
}, nil
},
CreateLabelMappingFn: func(ctx context.Context, lm *influxdb.LabelMapping) error {
return nil
},
@ -840,6 +896,12 @@ func TestLabelService_CreateLabelMapping(t *testing.T) {
name: "unauthorized to create label mapping",
fields: fields{
LabelService: &mock.LabelService{
FindLabelByIDFn: func(ctx context.Context, id influxdb.ID) (*influxdb.Label, error) {
return &influxdb.Label{
ID: 1,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
}, nil
},
CreateLabelMappingFn: func(ctx context.Context, lm *influxdb.LabelMapping) error {
return nil
},
@ -862,7 +924,7 @@ func TestLabelService_CreateLabelMapping(t *testing.T) {
},
wants: wants{
err: &influxdb.Error{
Msg: "write:labels/0000000000000001 is unauthorized",
Msg: "write:orgs/020f755c3c083000/labels/0000000000000001 is unauthorized",
Code: influxdb.EUnauthorized,
},
},
@ -906,7 +968,8 @@ func TestLabelService_DeleteLabelMapping(t *testing.T) {
LabelService: &mock.LabelService{
FindLabelByIDFn: func(ctc context.Context, id influxdb.ID) (*influxdb.Label, error) {
return &influxdb.Label{
ID: 1,
ID: 1,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
}, nil
},
DeleteLabelMappingFn: func(ctx context.Context, m *influxdb.LabelMapping) error {
@ -946,7 +1009,8 @@ func TestLabelService_DeleteLabelMapping(t *testing.T) {
LabelService: &mock.LabelService{
FindLabelByIDFn: func(ctc context.Context, id influxdb.ID) (*influxdb.Label, error) {
return &influxdb.Label{
ID: 1,
ID: 1,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
}, nil
},
DeleteLabelMappingFn: func(ctx context.Context, m *influxdb.LabelMapping) error {
@ -982,7 +1046,8 @@ func TestLabelService_DeleteLabelMapping(t *testing.T) {
LabelService: &mock.LabelService{
FindLabelByIDFn: func(ctc context.Context, id influxdb.ID) (*influxdb.Label, error) {
return &influxdb.Label{
ID: 1,
ID: 1,
OrganizationID: influxdbtesting.MustIDBase16(orgOneID),
}, nil
},
DeleteLabelMappingFn: func(ctx context.Context, m *influxdb.LabelMapping) error {
@ -1007,7 +1072,7 @@ func TestLabelService_DeleteLabelMapping(t *testing.T) {
},
wants: wants{
err: &influxdb.Error{
Msg: "write:labels/0000000000000001 is unauthorized",
Msg: "write:orgs/020f755c3c083000/labels/0000000000000001 is unauthorized",
Code: influxdb.EUnauthorized,
},
},

View File

@ -78,9 +78,16 @@ func (b postLabelRequest) Validate() error {
Msg: "label requires a name",
}
}
if !b.Label.OrganizationID.Valid() {
return &platform.Error{
Code: platform.EInvalid,
Msg: "label requires a valid orgID",
}
}
return nil
}
// TODO(jm): ensure that the specified org actually exists
func decodePostLabelRequest(ctx context.Context, r *http.Request) (*postLabelRequest, error) {
l := &platform.Label{}
if err := json.NewDecoder(r.Body).Decode(l); err != nil {

View File

@ -282,7 +282,8 @@ func TestService_handlePostLabel(t *testing.T) {
},
args: args{
label: &platform.Label{
Name: "mylabel",
Name: "mylabel",
OrganizationID: platformtesting.MustIDBase16("020f755c3c082008"),
},
},
wants: wants{
@ -295,7 +296,8 @@ func TestService_handlePostLabel(t *testing.T) {
},
"label": {
"id": "020f755c3c082000",
"name": "mylabel"
"name": "mylabel",
"orgID": "020f755c3c082008"
}
}
`,

View File

@ -1638,7 +1638,7 @@ paths:
content:
application/json:
schema:
$ref: "#/components/schemas/Label"
$ref: "#/components/schemas/LabelCreateRequest"
responses:
'201':
description: Added label
@ -7538,6 +7538,22 @@ components:
id:
readOnly: true
type: string
orgID:
readOnly: true
type: string
name:
type: string
properties:
type: object
additionalProperties:
type: string
description: Key/Value pairs associated with this label. Keys can be removed by sending an update with an empty value.
example: {"color": "ffb3b3", "description": "this is a description"}
LabelCreateRequest:
type: object
properties:
orgID:
type: string
name:
type: string
properties:

View File

@ -6,6 +6,7 @@ import (
"encoding/json"
"github.com/influxdata/influxdb"
"github.com/influxdata/influxdb/kit/tracing"
)
var (
@ -248,7 +249,15 @@ func (s *Service) CreateLabel(ctx context.Context, l *influxdb.Label) error {
err := s.kv.Update(ctx, func(tx Tx) error {
l.ID = s.IDGenerator.ID()
return s.putLabel(ctx, tx, l)
if err := s.putLabel(ctx, tx, l); err != nil {
return err
}
if err := s.createLabelUserResourceMappings(ctx, tx, l); err != nil {
return err
}
return nil
})
if err != nil {
@ -271,6 +280,36 @@ func (s *Service) PutLabel(ctx context.Context, l *influxdb.Label) error {
})
}
func (s *Service) createLabelUserResourceMappings(ctx context.Context, tx Tx, l *influxdb.Label) error {
span, ctx := tracing.StartSpanFromContext(ctx)
defer span.Finish()
ms, err := s.findUserResourceMappings(ctx, tx, influxdb.UserResourceMappingFilter{
ResourceType: influxdb.OrgsResourceType,
ResourceID: l.OrganizationID,
})
if err != nil {
return &influxdb.Error{
Err: err,
}
}
for _, m := range ms {
if err := s.createUserResourceMapping(ctx, tx, &influxdb.UserResourceMapping{
ResourceType: influxdb.LabelsResourceType,
ResourceID: l.ID,
UserID: m.UserID,
UserType: m.UserType,
}); err != nil {
return &influxdb.Error{
Err: err,
}
}
}
return nil
}
func labelMappingKey(m *influxdb.LabelMapping) ([]byte, error) {
lid, err := m.LabelID.Encode()
if err != nil {
@ -475,5 +514,18 @@ func (s *Service) deleteLabel(ctx context.Context, tx Tx, id influxdb.ID) error
return err
}
return b.Delete(encodedID)
if err := b.Delete(encodedID); err != nil {
return &influxdb.Error{
Err: err,
}
}
if err := s.deleteUserResourceMappings(ctx, tx, influxdb.UserResourceMappingFilter{
ResourceID: id,
ResourceType: influxdb.LabelsResourceType,
}); err != nil {
return err
}
return nil
}

View File

@ -47,9 +47,10 @@ type LabelService interface {
// Label is a tag set on a resource, typically used for filtering on a UI.
type Label struct {
ID ID `json:"id,omitempty"`
Name string `json:"name"`
Properties map[string]string `json:"properties,omitempty"`
ID ID `json:"id,omitempty"`
OrganizationID ID `json:"orgID,omitempty"`
Name string `json:"name"`
Properties map[string]string `json:"properties,omitempty"`
}
// Validate returns an error if the label is invalid.
@ -61,6 +62,13 @@ func (l *Label) Validate() error {
}
}
if !l.OrganizationID.Valid() {
return &Error{
Code: EInvalid,
Msg: "organization ID is required",
}
}
return nil
}
@ -105,7 +113,8 @@ type LabelUpdate struct {
// LabelFilter represents a set of filters that restrict the returned results.
type LabelFilter struct {
Name string
Name string
OrgID *ID
}
// LabelMappingFilter represents a set of filters that restrict the returned results.

View File

@ -3,13 +3,19 @@ package influxdb_test
import (
"testing"
"github.com/influxdata/influxdb"
platform "github.com/influxdata/influxdb"
influxtest "github.com/influxdata/influxdb/testing"
)
const (
orgOneID = "020f755c3c083000"
)
func TestLabelValidate(t *testing.T) {
type fields struct {
ResourceID platform.ID
Name string
Name string
OrgID influxdb.ID
}
tests := []struct {
name string
@ -19,19 +25,30 @@ func TestLabelValidate(t *testing.T) {
{
name: "valid label",
fields: fields{
Name: "iot",
Name: "iot",
OrgID: influxtest.MustIDBase16(orgOneID),
},
},
{
name: "label requires a name",
fields: fields{},
name: "label requires a name",
fields: fields{
OrgID: influxtest.MustIDBase16(orgOneID),
},
wantErr: true,
},
{
name: "label requires an organization ID",
fields: fields{
Name: "iot",
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
m := platform.Label{
Name: tt.fields.Name,
Name: tt.fields.Name,
OrganizationID: tt.fields.OrgID,
}
if err := m.Validate(); (err != nil) != tt.wantErr {
t.Errorf("Label.Validate() error = %v, wantErr %v", err, tt.wantErr)

View File

@ -345,8 +345,9 @@ func UpdateLabel(
fields: LabelFields{
Labels: []*influxdb.Label{
{
ID: MustIDBase16(labelOneID),
Name: "Tag1",
ID: MustIDBase16(labelOneID),
OrganizationID: MustIDBase16(orgOneID),
Name: "Tag1",
},
},
},
@ -359,8 +360,9 @@ func UpdateLabel(
wants: wants{
labels: []*influxdb.Label{
{
ID: MustIDBase16(labelOneID),
Name: "NotTag1",
ID: MustIDBase16(labelOneID),
OrganizationID: MustIDBase16(orgOneID),
Name: "NotTag1",
},
},
},
@ -370,8 +372,9 @@ func UpdateLabel(
fields: LabelFields{
Labels: []*influxdb.Label{
{
ID: MustIDBase16(labelOneID),
Name: "Tag1",
ID: MustIDBase16(labelOneID),
OrganizationID: MustIDBase16(orgOneID),
Name: "Tag1",
},
},
},
@ -386,8 +389,9 @@ func UpdateLabel(
wants: wants{
labels: []*influxdb.Label{
{
ID: MustIDBase16(labelOneID),
Name: "Tag1",
ID: MustIDBase16(labelOneID),
OrganizationID: MustIDBase16(orgOneID),
Name: "Tag1",
Properties: map[string]string{
"color": "fff000",
},
@ -400,8 +404,9 @@ func UpdateLabel(
fields: LabelFields{
Labels: []*influxdb.Label{
{
ID: MustIDBase16(labelOneID),
Name: "Tag1",
ID: MustIDBase16(labelOneID),
OrganizationID: MustIDBase16(orgOneID),
Name: "Tag1",
Properties: map[string]string{
"color": "fff000",
"description": "description",
@ -420,8 +425,9 @@ func UpdateLabel(
wants: wants{
labels: []*influxdb.Label{
{
ID: MustIDBase16(labelOneID),
Name: "Tag1",
ID: MustIDBase16(labelOneID),
OrganizationID: MustIDBase16(orgOneID),
Name: "Tag1",
Properties: map[string]string{
"color": "abc123",
"description": "description",
@ -435,8 +441,9 @@ func UpdateLabel(
fields: LabelFields{
Labels: []*influxdb.Label{
{
ID: MustIDBase16(labelOneID),
Name: "Tag1",
ID: MustIDBase16(labelOneID),
OrganizationID: MustIDBase16(orgOneID),
Name: "Tag1",
Properties: map[string]string{
"color": "fff000",
"description": "description",
@ -455,8 +462,9 @@ func UpdateLabel(
wants: wants{
labels: []*influxdb.Label{
{
ID: MustIDBase16(labelOneID),
Name: "Tag1",
ID: MustIDBase16(labelOneID),
OrganizationID: MustIDBase16(orgOneID),
Name: "Tag1",
Properties: map[string]string{
"color": "fff000",
},
@ -530,12 +538,14 @@ func DeleteLabel(
fields: LabelFields{
Labels: []*influxdb.Label{
{
ID: MustIDBase16(labelOneID),
Name: "Tag1",
ID: MustIDBase16(labelOneID),
OrganizationID: MustIDBase16(orgOneID),
Name: "Tag1",
},
{
ID: MustIDBase16(labelTwoID),
Name: "Tag2",
ID: MustIDBase16(labelTwoID),
OrganizationID: MustIDBase16(orgOneID),
Name: "Tag2",
},
},
},
@ -545,8 +555,9 @@ func DeleteLabel(
wants: wants{
labels: []*influxdb.Label{
{
ID: MustIDBase16(labelTwoID),
Name: "Tag2",
ID: MustIDBase16(labelTwoID),
OrganizationID: MustIDBase16(orgOneID),
Name: "Tag2",
},
},
},
@ -556,8 +567,9 @@ func DeleteLabel(
fields: LabelFields{
Labels: []*influxdb.Label{
{
ID: MustIDBase16(labelOneID),
Name: "Tag1",
ID: MustIDBase16(labelOneID),
OrganizationID: MustIDBase16(orgOneID),
Name: "Tag1",
},
},
},
@ -567,8 +579,9 @@ func DeleteLabel(
wants: wants{
labels: []*influxdb.Label{
{
ID: MustIDBase16(labelOneID),
Name: "Tag1",
ID: MustIDBase16(labelOneID),
OrganizationID: MustIDBase16(orgOneID),
Name: "Tag1",
},
},
err: &influxdb.Error{