Merge pull request #11763 from influxdata/fix/label-auth

Pass resource type to generic resource handler for labels
pull/11764/head v2.0.0-alpha.2
Michael Desa 2019-02-07 19:18:07 -05:00 committed by GitHub
commit 9aeca07e96
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 384 additions and 174 deletions

View File

@ -9,7 +9,7 @@ import (
"path"
"time"
platform "github.com/influxdata/influxdb"
"github.com/influxdata/influxdb"
"github.com/julienschmidt/httprouter"
"go.uber.org/zap"
)
@ -19,12 +19,12 @@ import (
type BucketBackend struct {
Logger *zap.Logger
BucketService platform.BucketService
BucketOperationLogService platform.BucketOperationLogService
UserResourceMappingService platform.UserResourceMappingService
LabelService platform.LabelService
UserService platform.UserService
OrganizationService platform.OrganizationService
BucketService influxdb.BucketService
BucketOperationLogService influxdb.BucketOperationLogService
UserResourceMappingService influxdb.UserResourceMappingService
LabelService influxdb.LabelService
UserService influxdb.UserService
OrganizationService influxdb.OrganizationService
}
// NewBucketBackend returns a new instance of BucketBackend.
@ -47,12 +47,12 @@ type BucketHandler struct {
Logger *zap.Logger
BucketService platform.BucketService
BucketOperationLogService platform.BucketOperationLogService
UserResourceMappingService platform.UserResourceMappingService
LabelService platform.LabelService
UserService platform.UserService
OrganizationService platform.OrganizationService
BucketService influxdb.BucketService
BucketOperationLogService influxdb.BucketOperationLogService
UserResourceMappingService influxdb.UserResourceMappingService
LabelService influxdb.LabelService
UserService influxdb.UserService
OrganizationService influxdb.OrganizationService
}
const (
@ -90,8 +90,8 @@ func NewBucketHandler(b *BucketBackend) *BucketHandler {
memberBackend := MemberBackend{
Logger: b.Logger.With(zap.String("handler", "member")),
ResourceType: platform.BucketsResourceType,
UserType: platform.Member,
ResourceType: influxdb.BucketsResourceType,
UserType: influxdb.Member,
UserResourceMappingService: b.UserResourceMappingService,
UserService: b.UserService,
}
@ -101,8 +101,8 @@ func NewBucketHandler(b *BucketBackend) *BucketHandler {
ownerBackend := MemberBackend{
Logger: b.Logger.With(zap.String("handler", "member")),
ResourceType: platform.BucketsResourceType,
UserType: platform.Owner,
ResourceType: influxdb.BucketsResourceType,
UserType: influxdb.Owner,
UserResourceMappingService: b.UserResourceMappingService,
UserService: b.UserService,
}
@ -113,6 +113,7 @@ func NewBucketHandler(b *BucketBackend) *BucketHandler {
labelBackend := &LabelBackend{
Logger: b.Logger.With(zap.String("handler", "label")),
LabelService: b.LabelService,
ResourceType: influxdb.BucketsResourceType,
}
h.HandlerFunc("GET", bucketsIDLabelsPath, newGetLabelsHandler(labelBackend))
h.HandlerFunc("POST", bucketsIDLabelsPath, newPostLabelHandler(labelBackend))
@ -124,8 +125,8 @@ func NewBucketHandler(b *BucketBackend) *BucketHandler {
// bucket is used for serialization/deserialization with duration string syntax.
type bucket struct {
ID platform.ID `json:"id,omitempty"`
OrganizationID platform.ID `json:"organizationID,omitempty"`
ID influxdb.ID `json:"id,omitempty"`
OrganizationID influxdb.ID `json:"organizationID,omitempty"`
Organization string `json:"organization,omitempty"`
Name string `json:"name"`
RetentionPolicyName string `json:"rp,omitempty"` // This to support v1 sources
@ -138,7 +139,7 @@ type retentionRule struct {
EverySeconds int64 `json:"everySeconds"`
}
func (b *bucket) toPlatform() (*platform.Bucket, error) {
func (b *bucket) toInfluxDB() (*influxdb.Bucket, error) {
if b == nil {
return nil, nil
}
@ -149,14 +150,14 @@ func (b *bucket) toPlatform() (*platform.Bucket, error) {
if len(b.RetentionRules) > 0 {
d = time.Duration(b.RetentionRules[0].EverySeconds) * time.Second
if d < time.Second {
return nil, &platform.Error{
Code: platform.EUnprocessableEntity,
return nil, &influxdb.Error{
Code: influxdb.EUnprocessableEntity,
Msg: "expiration seconds must be greater than or equal to one second",
}
}
}
return &platform.Bucket{
return &influxdb.Bucket{
ID: b.ID,
OrganizationID: b.OrganizationID,
Organization: b.Organization,
@ -166,7 +167,7 @@ func (b *bucket) toPlatform() (*platform.Bucket, error) {
}, nil
}
func newBucket(pb *platform.Bucket) *bucket {
func newBucket(pb *influxdb.Bucket) *bucket {
if pb == nil {
return nil
}
@ -196,7 +197,7 @@ type bucketUpdate struct {
RetentionRules []retentionRule `json:"retentionRules,omitempty"`
}
func (b *bucketUpdate) toPlatform() (*platform.BucketUpdate, error) {
func (b *bucketUpdate) toInfluxDB() (*influxdb.BucketUpdate, error) {
if b == nil {
return nil, nil
}
@ -206,20 +207,20 @@ func (b *bucketUpdate) toPlatform() (*platform.BucketUpdate, error) {
if len(b.RetentionRules) > 0 {
d = time.Duration(b.RetentionRules[0].EverySeconds) * time.Second
if d < time.Second {
return nil, &platform.Error{
Code: platform.EUnprocessableEntity,
return nil, &influxdb.Error{
Code: influxdb.EUnprocessableEntity,
Msg: "expiration seconds must be greater than or equal to one second",
}
}
}
return &platform.BucketUpdate{
return &influxdb.BucketUpdate{
Name: b.Name,
RetentionPeriod: &d,
}, nil
}
func newBucketUpdate(pb *platform.BucketUpdate) *bucketUpdate {
func newBucketUpdate(pb *influxdb.BucketUpdate) *bucketUpdate {
if pb == nil {
return nil
}
@ -242,10 +243,10 @@ func newBucketUpdate(pb *platform.BucketUpdate) *bucketUpdate {
type bucketResponse struct {
Links map[string]string `json:"links"`
bucket
Labels []platform.Label `json:"labels"`
Labels []influxdb.Label `json:"labels"`
}
func newBucketResponse(b *platform.Bucket, labels []*platform.Label) *bucketResponse {
func newBucketResponse(b *influxdb.Bucket, labels []*influxdb.Label) *bucketResponse {
res := &bucketResponse{
Links: map[string]string{
"self": fmt.Sprintf("/api/v2/buckets/%s", b.ID),
@ -254,7 +255,7 @@ func newBucketResponse(b *platform.Bucket, labels []*platform.Label) *bucketResp
"org": fmt.Sprintf("/api/v2/orgs/%s", b.OrganizationID),
},
bucket: *newBucket(b),
Labels: []platform.Label{},
Labels: []influxdb.Label{},
}
for _, l := range labels {
@ -265,14 +266,14 @@ func newBucketResponse(b *platform.Bucket, labels []*platform.Label) *bucketResp
}
type bucketsResponse struct {
Links *platform.PagingLinks `json:"links"`
Links *influxdb.PagingLinks `json:"links"`
Buckets []*bucketResponse `json:"buckets"`
}
func newBucketsResponse(ctx context.Context, opts platform.FindOptions, f platform.BucketFilter, bs []*platform.Bucket, labelService platform.LabelService) *bucketsResponse {
func newBucketsResponse(ctx context.Context, opts influxdb.FindOptions, f influxdb.BucketFilter, bs []*influxdb.Bucket, labelService influxdb.LabelService) *bucketsResponse {
rs := make([]*bucketResponse, 0, len(bs))
for _, b := range bs {
labels, _ := labelService.FindResourceLabels(ctx, platform.LabelMappingFilter{ResourceID: b.ID})
labels, _ := labelService.FindResourceLabels(ctx, influxdb.LabelMappingFilter{ResourceID: b.ID})
rs = append(rs, newBucketResponse(b, labels))
}
return &bucketsResponse{
@ -293,7 +294,7 @@ func (h *BucketHandler) handlePostBucket(w http.ResponseWriter, r *http.Request)
if !req.Bucket.OrganizationID.Valid() {
// Resolve organization name to ID before create
o, err := h.OrganizationService.FindOrganization(ctx, platform.OrganizationFilter{Name: &req.Bucket.Organization})
o, err := h.OrganizationService.FindOrganization(ctx, influxdb.OrganizationFilter{Name: &req.Bucket.Organization})
if err != nil {
EncodeError(ctx, err, w)
return
@ -306,14 +307,14 @@ func (h *BucketHandler) handlePostBucket(w http.ResponseWriter, r *http.Request)
return
}
if err := encodeResponse(ctx, w, http.StatusCreated, newBucketResponse(req.Bucket, []*platform.Label{})); err != nil {
if err := encodeResponse(ctx, w, http.StatusCreated, newBucketResponse(req.Bucket, []*influxdb.Label{})); err != nil {
logEncodingError(h.Logger, r, err)
return
}
}
type postBucketRequest struct {
Bucket *platform.Bucket
Bucket *influxdb.Bucket
}
func (b postBucketRequest) Validate() error {
@ -329,7 +330,7 @@ func decodePostBucketRequest(ctx context.Context, r *http.Request) (*postBucketR
return nil, err
}
pb, err := b.toPlatform()
pb, err := b.toInfluxDB()
if err != nil {
return nil, err
}
@ -357,7 +358,7 @@ func (h *BucketHandler) handleGetBucket(w http.ResponseWriter, r *http.Request)
return
}
labels, err := h.LabelService.FindResourceLabels(ctx, platform.LabelMappingFilter{ResourceID: b.ID})
labels, err := h.LabelService.FindResourceLabels(ctx, influxdb.LabelMappingFilter{ResourceID: b.ID})
if err != nil {
EncodeError(ctx, err, w)
return
@ -370,20 +371,20 @@ func (h *BucketHandler) handleGetBucket(w http.ResponseWriter, r *http.Request)
}
type getBucketRequest struct {
BucketID platform.ID
BucketID influxdb.ID
}
func decodeGetBucketRequest(ctx context.Context, r *http.Request) (*getBucketRequest, error) {
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, &platform.Error{
Code: platform.EInvalid,
return nil, &influxdb.Error{
Code: influxdb.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
var i influxdb.ID
if err := i.DecodeFromString(id); err != nil {
return nil, err
}
@ -413,20 +414,20 @@ func (h *BucketHandler) handleDeleteBucket(w http.ResponseWriter, r *http.Reques
}
type deleteBucketRequest struct {
BucketID platform.ID
BucketID influxdb.ID
}
func decodeDeleteBucketRequest(ctx context.Context, r *http.Request) (*deleteBucketRequest, error) {
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, &platform.Error{
Code: platform.EInvalid,
return nil, &influxdb.Error{
Code: influxdb.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
var i influxdb.ID
if err := i.DecodeFromString(id); err != nil {
return nil, err
}
@ -460,8 +461,8 @@ func (h *BucketHandler) handleGetBuckets(w http.ResponseWriter, r *http.Request)
}
type getBucketsRequest struct {
filter platform.BucketFilter
opts platform.FindOptions
filter influxdb.BucketFilter
opts influxdb.FindOptions
}
func decodeGetBucketsRequest(ctx context.Context, r *http.Request) (*getBucketsRequest, error) {
@ -476,7 +477,7 @@ func decodeGetBucketsRequest(ctx context.Context, r *http.Request) (*getBucketsR
req.opts = *opts
if orgID := qp.Get("orgID"); orgID != "" {
id, err := platform.IDFromString(orgID)
id, err := influxdb.IDFromString(orgID)
if err != nil {
return nil, err
}
@ -492,7 +493,7 @@ func decodeGetBucketsRequest(ctx context.Context, r *http.Request) (*getBucketsR
}
if bucketID := qp.Get("id"); bucketID != "" {
id, err := platform.IDFromString(bucketID)
id, err := influxdb.IDFromString(bucketID)
if err != nil {
return nil, err
}
@ -518,7 +519,7 @@ func (h *BucketHandler) handlePatchBucket(w http.ResponseWriter, r *http.Request
return
}
labels, err := h.LabelService.FindResourceLabels(ctx, platform.LabelMappingFilter{ResourceID: b.ID})
labels, err := h.LabelService.FindResourceLabels(ctx, influxdb.LabelMappingFilter{ResourceID: b.ID})
if err != nil {
EncodeError(ctx, err, w)
return
@ -531,37 +532,37 @@ func (h *BucketHandler) handlePatchBucket(w http.ResponseWriter, r *http.Request
}
type patchBucketRequest struct {
Update platform.BucketUpdate
BucketID platform.ID
Update influxdb.BucketUpdate
BucketID influxdb.ID
}
func decodePatchBucketRequest(ctx context.Context, r *http.Request) (*patchBucketRequest, error) {
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, &platform.Error{
Code: platform.EInvalid,
return nil, &influxdb.Error{
Code: influxdb.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
var i influxdb.ID
if err := i.DecodeFromString(id); err != nil {
return nil, &platform.Error{
Code: platform.EInvalid,
return nil, &influxdb.Error{
Code: influxdb.EInvalid,
Msg: err.Error(),
}
}
bu := &bucketUpdate{}
if err := json.NewDecoder(r.Body).Decode(bu); err != nil {
return nil, &platform.Error{
Code: platform.EInvalid,
return nil, &influxdb.Error{
Code: influxdb.EInvalid,
Msg: err.Error(),
}
}
upd, err := bu.toPlatform()
upd, err := bu.toInfluxDB()
if err != nil {
return nil, err
}
@ -587,7 +588,7 @@ type BucketService struct {
}
// FindBucketByID returns a single bucket by ID.
func (s *BucketService) FindBucketByID(ctx context.Context, id platform.ID) (*platform.Bucket, error) {
func (s *BucketService) FindBucketByID(ctx context.Context, id influxdb.ID) (*influxdb.Bucket, error) {
u, err := newURL(s.Addr, bucketIDPath(id))
if err != nil {
return nil, err
@ -614,20 +615,20 @@ func (s *BucketService) FindBucketByID(ctx context.Context, id platform.ID) (*pl
if err := json.NewDecoder(resp.Body).Decode(&br); err != nil {
return nil, err
}
return br.toPlatform()
return br.toInfluxDB()
}
// FindBucket returns the first bucket that matches filter.
func (s *BucketService) FindBucket(ctx context.Context, filter platform.BucketFilter) (*platform.Bucket, error) {
func (s *BucketService) FindBucket(ctx context.Context, filter influxdb.BucketFilter) (*influxdb.Bucket, error) {
bs, n, err := s.FindBuckets(ctx, filter)
if err != nil {
return nil, err
}
if n == 0 {
return nil, &platform.Error{
Code: platform.ENotFound,
Op: s.OpPrefix + platform.OpFindBucket,
return nil, &influxdb.Error{
Code: influxdb.ENotFound,
Op: s.OpPrefix + influxdb.OpFindBucket,
Msg: "bucket not found",
}
}
@ -637,7 +638,7 @@ func (s *BucketService) FindBucket(ctx context.Context, filter platform.BucketFi
// FindBuckets returns a list of buckets that match filter and the total count of matching buckets.
// Additional options provide pagination & sorting.
func (s *BucketService) FindBuckets(ctx context.Context, filter platform.BucketFilter, opt ...platform.FindOptions) ([]*platform.Bucket, int, error) {
func (s *BucketService) FindBuckets(ctx context.Context, filter influxdb.BucketFilter, opt ...influxdb.FindOptions) ([]*influxdb.Bucket, int, error) {
u, err := newURL(s.Addr, bucketPath)
if err != nil {
return nil, 0, err
@ -689,9 +690,9 @@ func (s *BucketService) FindBuckets(ctx context.Context, filter platform.BucketF
return nil, 0, err
}
buckets := make([]*platform.Bucket, 0, len(bs.Buckets))
buckets := make([]*influxdb.Bucket, 0, len(bs.Buckets))
for _, b := range bs.Buckets {
pb, err := b.bucket.toPlatform()
pb, err := b.bucket.toInfluxDB()
if err != nil {
return nil, 0, err
}
@ -703,7 +704,7 @@ func (s *BucketService) FindBuckets(ctx context.Context, filter platform.BucketF
}
// CreateBucket creates a new bucket and sets b.ID with the new identifier.
func (s *BucketService) CreateBucket(ctx context.Context, b *platform.Bucket) error {
func (s *BucketService) CreateBucket(ctx context.Context, b *influxdb.Bucket) error {
u, err := newURL(s.Addr, bucketPath)
if err != nil {
return err
@ -740,7 +741,7 @@ func (s *BucketService) CreateBucket(ctx context.Context, b *platform.Bucket) er
return err
}
pb, err := br.toPlatform()
pb, err := br.toInfluxDB()
if err != nil {
return err
}
@ -750,7 +751,7 @@ func (s *BucketService) CreateBucket(ctx context.Context, b *platform.Bucket) er
// UpdateBucket updates a single bucket with changeset.
// Returns the new bucket state after update.
func (s *BucketService) UpdateBucket(ctx context.Context, id platform.ID, upd platform.BucketUpdate) (*platform.Bucket, error) {
func (s *BucketService) UpdateBucket(ctx context.Context, id influxdb.ID, upd influxdb.BucketUpdate) (*influxdb.Bucket, error) {
u, err := newURL(s.Addr, bucketIDPath(id))
if err != nil {
return nil, err
@ -786,11 +787,11 @@ func (s *BucketService) UpdateBucket(ctx context.Context, id platform.ID, upd pl
if err := json.NewDecoder(resp.Body).Decode(&br); err != nil {
return nil, err
}
return br.toPlatform()
return br.toInfluxDB()
}
// DeleteBucket removes a bucket by ID.
func (s *BucketService) DeleteBucket(ctx context.Context, id platform.ID) error {
func (s *BucketService) DeleteBucket(ctx context.Context, id influxdb.ID) error {
u, err := newURL(s.Addr, bucketIDPath(id))
if err != nil {
return err
@ -812,7 +813,7 @@ func (s *BucketService) DeleteBucket(ctx context.Context, id platform.ID) error
return CheckError(resp)
}
func bucketIDPath(id platform.ID) string {
func bucketIDPath(id influxdb.ID) string {
return path.Join(bucketPath, id.String())
}
@ -839,21 +840,21 @@ func (h *BucketHandler) handleGetBucketLog(w http.ResponseWriter, r *http.Reques
}
type getBucketLogRequest struct {
BucketID platform.ID
opts platform.FindOptions
BucketID influxdb.ID
opts influxdb.FindOptions
}
func decodeGetBucketLogRequest(ctx context.Context, r *http.Request) (*getBucketLogRequest, error) {
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, &platform.Error{
Code: platform.EInvalid,
return nil, &influxdb.Error{
Code: influxdb.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
var i influxdb.ID
if err := i.DecodeFromString(id); err != nil {
return nil, err
}
@ -869,7 +870,7 @@ func decodeGetBucketLogRequest(ctx context.Context, r *http.Request) (*getBucket
}, nil
}
func newBucketLogResponse(id platform.ID, es []*platform.OperationLogEntry) *operationLogResponse {
func newBucketLogResponse(id influxdb.ID, es []*influxdb.OperationLogEntry) *operationLogResponse {
log := make([]*operationLogEntryResponse, 0, len(es))
for _, e := range es {
log = append(log, newOperationLogEntryResponse(e))

View File

@ -119,6 +119,7 @@ func NewDashboardHandler(b *DashboardBackend) *DashboardHandler {
labelBackend := &LabelBackend{
Logger: b.Logger.With(zap.String("handler", "label")),
LabelService: b.LabelService,
ResourceType: platform.DashboardsResourceType,
}
h.HandlerFunc("GET", dashboardsIDLabelsPath, newGetLabelsHandler(labelBackend))
h.HandlerFunc("POST", dashboardsIDLabelsPath, newPostLabelHandler(labelBackend))

View File

@ -5,13 +5,14 @@ import (
"context"
"encoding/json"
"fmt"
"go.uber.org/zap"
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"
"time"
"go.uber.org/zap"
platform "github.com/influxdata/influxdb"
"github.com/influxdata/influxdb/inmem"
"github.com/influxdata/influxdb/mock"
@ -1287,3 +1288,101 @@ func TestDashboardService(t *testing.T) {
t.Parallel()
platformtesting.DashboardService(initDashboardService, t)
}
func TestService_handlePostDashboardLabel(t *testing.T) {
type fields struct {
LabelService platform.LabelService
}
type args struct {
labelMapping *platform.LabelMapping
dashboardID platform.ID
}
type wants struct {
statusCode int
contentType string
body string
}
tests := []struct {
name string
fields fields
args args
wants wants
}{
{
name: "add label to dashboard",
fields: fields{
LabelService: &mock.LabelService{
FindLabelByIDFn: func(ctx context.Context, id platform.ID) (*platform.Label, error) {
return &platform.Label{
ID: 1,
Name: "label",
Properties: map[string]string{
"color": "fff000",
},
}, nil
},
CreateLabelMappingFn: func(ctx context.Context, m *platform.LabelMapping) error { return nil },
},
},
args: args{
labelMapping: &platform.LabelMapping{
ResourceID: 100,
LabelID: 1,
},
dashboardID: 100,
},
wants: wants{
statusCode: http.StatusCreated,
contentType: "application/json; charset=utf-8",
body: `
{
"label": {
"id": "0000000000000001",
"name": "label",
"properties": {
"color": "fff000"
}
},
"links": {
"self": "/api/v2/labels/0000000000000001"
}
}
`,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
dashboardBackend := NewMockDashboardBackend()
dashboardBackend.LabelService = tt.fields.LabelService
h := NewDashboardHandler(dashboardBackend)
b, err := json.Marshal(tt.args.labelMapping)
if err != nil {
t.Fatalf("failed to unmarshal label mapping: %v", err)
}
url := fmt.Sprintf("http://localhost:9999/api/v2/dashboards/%s/labels", tt.args.dashboardID)
r := httptest.NewRequest("POST", url, bytes.NewReader(b))
w := httptest.NewRecorder()
h.ServeHTTP(w, r)
res := w.Result()
content := res.Header.Get("Content-Type")
body, _ := ioutil.ReadAll(res.Body)
if res.StatusCode != tt.wants.statusCode {
t.Errorf("got %v, want %v", res.StatusCode, tt.wants.statusCode)
}
if tt.wants.contentType != "" && content != tt.wants.contentType {
t.Errorf("got %v, want %v", content, tt.wants.contentType)
}
if eq, diff, _ := jsonEqual(string(body), tt.wants.body); tt.wants.body != "" && !eq {
t.Errorf("Diff\n%s", diff)
}
})
}
}

View File

@ -5,10 +5,11 @@ import (
"context"
"encoding/json"
"fmt"
"go.uber.org/zap"
"net/http"
"path"
"go.uber.org/zap"
platform "github.com/influxdata/influxdb"
"github.com/julienschmidt/httprouter"
)
@ -299,6 +300,7 @@ func newLabelsResponse(ls []*platform.Label) *labelsResponse {
type LabelBackend struct {
Logger *zap.Logger
LabelService platform.LabelService
ResourceType platform.ResourceType
}
// newGetLabelsHandler returns a handler func for a GET to /labels endpoints
@ -306,7 +308,7 @@ func newGetLabelsHandler(b *LabelBackend) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
req, err := decodeGetLabelsRequest(ctx, r)
req, err := decodeGetLabelsRequest(ctx, r, b.ResourceType)
if err != nil {
EncodeError(ctx, err, w)
return
@ -329,7 +331,7 @@ type getLabelsRequest struct {
filter platform.LabelMappingFilter
}
func decodeGetLabelsRequest(ctx context.Context, r *http.Request) (*getLabelsRequest, error) {
func decodeGetLabelsRequest(ctx context.Context, r *http.Request, rt platform.ResourceType) (*getLabelsRequest, error) {
req := &getLabelsRequest{}
params := httprouter.ParamsFromContext(ctx)
@ -346,6 +348,7 @@ func decodeGetLabelsRequest(ctx context.Context, r *http.Request) (*getLabelsReq
return nil, err
}
req.filter.ResourceID = i
req.filter.ResourceType = rt
return req, nil
}
@ -355,7 +358,7 @@ func newPostLabelHandler(b *LabelBackend) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
req, err := decodePostLabelMappingRequest(ctx, r)
req, err := decodePostLabelMappingRequest(ctx, r, b.ResourceType)
if err != nil {
EncodeError(ctx, err, w)
return
@ -388,7 +391,7 @@ type postLabelMappingRequest struct {
Mapping platform.LabelMapping
}
func decodePostLabelMappingRequest(ctx context.Context, r *http.Request) (*postLabelMappingRequest, error) {
func decodePostLabelMappingRequest(ctx context.Context, r *http.Request, rt platform.ResourceType) (*postLabelMappingRequest, error) {
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
@ -409,6 +412,7 @@ func decodePostLabelMappingRequest(ctx context.Context, r *http.Request) (*postL
}
mapping.ResourceID = rid
mapping.ResourceType = rt
if err := mapping.Validate(); err != nil {
return nil, err
@ -457,8 +461,9 @@ func newDeleteLabelHandler(b *LabelBackend) http.HandlerFunc {
}
mapping := &platform.LabelMapping{
LabelID: req.LabelID,
ResourceID: req.ResourceID,
LabelID: req.LabelID,
ResourceID: req.ResourceID,
ResourceType: b.ResourceType,
}
if err := b.LabelService.DeleteLabelMapping(ctx, mapping); err != nil {

View File

@ -192,7 +192,7 @@ func (s *SetupService) Generate(ctx context.Context, or *platform.OnboardingRequ
return nil, err
}
bkt, err := oResp.Bucket.toPlatform()
bkt, err := oResp.Bucket.toInfluxDB()
if err != nil {
return nil, err
}

View File

@ -5,11 +5,12 @@ import (
"context"
"encoding/json"
"fmt"
platform "github.com/influxdata/influxdb"
"github.com/julienschmidt/httprouter"
"go.uber.org/zap"
"net/http"
"path"
"github.com/influxdata/influxdb"
"github.com/julienschmidt/httprouter"
"go.uber.org/zap"
)
// OrgBackend is all services and associated parameters required to construct
@ -17,12 +18,12 @@ import (
type OrgBackend struct {
Logger *zap.Logger
OrganizationService platform.OrganizationService
OrganizationOperationLogService platform.OrganizationOperationLogService
UserResourceMappingService platform.UserResourceMappingService
SecretService platform.SecretService
LabelService platform.LabelService
UserService platform.UserService
OrganizationService influxdb.OrganizationService
OrganizationOperationLogService influxdb.OrganizationOperationLogService
UserResourceMappingService influxdb.UserResourceMappingService
SecretService influxdb.SecretService
LabelService influxdb.LabelService
UserService influxdb.UserService
}
func NewOrgBackend(b *APIBackend) *OrgBackend {
@ -44,12 +45,12 @@ type OrgHandler struct {
Logger *zap.Logger
OrganizationService platform.OrganizationService
OrganizationOperationLogService platform.OrganizationOperationLogService
UserResourceMappingService platform.UserResourceMappingService
SecretService platform.SecretService
LabelService platform.LabelService
UserService platform.UserService
OrganizationService influxdb.OrganizationService
OrganizationOperationLogService influxdb.OrganizationOperationLogService
UserResourceMappingService influxdb.UserResourceMappingService
SecretService influxdb.SecretService
LabelService influxdb.LabelService
UserService influxdb.UserService
}
const (
@ -90,8 +91,8 @@ func NewOrgHandler(b *OrgBackend) *OrgHandler {
memberBackend := MemberBackend{
Logger: b.Logger.With(zap.String("handler", "member")),
ResourceType: platform.OrgsResourceType,
UserType: platform.Member,
ResourceType: influxdb.OrgsResourceType,
UserType: influxdb.Member,
UserResourceMappingService: b.UserResourceMappingService,
UserService: b.UserService,
}
@ -101,8 +102,8 @@ func NewOrgHandler(b *OrgBackend) *OrgHandler {
ownerBackend := MemberBackend{
Logger: b.Logger.With(zap.String("handler", "member")),
ResourceType: platform.OrgsResourceType,
UserType: platform.Owner,
ResourceType: influxdb.OrgsResourceType,
UserType: influxdb.Owner,
UserResourceMappingService: b.UserResourceMappingService,
UserService: b.UserService,
}
@ -118,6 +119,7 @@ func NewOrgHandler(b *OrgBackend) *OrgHandler {
labelBackend := &LabelBackend{
Logger: b.Logger.With(zap.String("handler", "label")),
LabelService: b.LabelService,
ResourceType: influxdb.OrgsResourceType,
}
h.HandlerFunc("GET", organizationsIDLabelsPath, newGetLabelsHandler(labelBackend))
h.HandlerFunc("POST", organizationsIDLabelsPath, newPostLabelHandler(labelBackend))
@ -132,15 +134,15 @@ type orgsResponse struct {
Organizations []*orgResponse `json:"orgs"`
}
func (o orgsResponse) ToPlatform() []*platform.Organization {
orgs := make([]*platform.Organization, len(o.Organizations))
func (o orgsResponse) Toinfluxdb() []*influxdb.Organization {
orgs := make([]*influxdb.Organization, len(o.Organizations))
for i := range o.Organizations {
orgs[i] = &o.Organizations[i].Organization
}
return orgs
}
func newOrgsResponse(orgs []*platform.Organization) *orgsResponse {
func newOrgsResponse(orgs []*influxdb.Organization) *orgsResponse {
res := orgsResponse{
Links: map[string]string{
"self": "/api/v2/orgs",
@ -155,10 +157,10 @@ func newOrgsResponse(orgs []*platform.Organization) *orgsResponse {
type orgResponse struct {
Links map[string]string `json:"links"`
platform.Organization
influxdb.Organization
}
func newOrgResponse(o *platform.Organization) *orgResponse {
func newOrgResponse(o *influxdb.Organization) *orgResponse {
return &orgResponse{
Links: map[string]string{
"self": fmt.Sprintf("/api/v2/orgs/%s", o.ID),
@ -179,7 +181,7 @@ type secretsResponse struct {
Secrets []string `json:"secrets"`
}
func newSecretsResponse(orgID platform.ID, ks []string) *secretsResponse {
func newSecretsResponse(orgID influxdb.ID, ks []string) *secretsResponse {
return &secretsResponse{
Links: map[string]string{
"org": fmt.Sprintf("/api/v2/orgs/%s", orgID),
@ -211,11 +213,11 @@ func (h *OrgHandler) handlePostOrg(w http.ResponseWriter, r *http.Request) {
}
type postOrgRequest struct {
Org *platform.Organization
Org *influxdb.Organization
}
func decodePostOrgRequest(ctx context.Context, r *http.Request) (*postOrgRequest, error) {
o := &platform.Organization{}
o := &influxdb.Organization{}
if err := json.NewDecoder(r.Body).Decode(o); err != nil {
return nil, err
}
@ -248,20 +250,20 @@ func (h *OrgHandler) handleGetOrg(w http.ResponseWriter, r *http.Request) {
}
type getOrgRequest struct {
OrgID platform.ID
OrgID influxdb.ID
}
func decodeGetOrgRequest(ctx context.Context, r *http.Request) (*getOrgRequest, error) {
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, &platform.Error{
Code: platform.EInvalid,
return nil, &influxdb.Error{
Code: influxdb.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
var i influxdb.ID
if err := i.DecodeFromString(id); err != nil {
return nil, err
}
@ -296,7 +298,7 @@ func (h *OrgHandler) handleGetOrgs(w http.ResponseWriter, r *http.Request) {
}
type getOrgsRequest struct {
filter platform.OrganizationFilter
filter influxdb.OrganizationFilter
}
func decodeGetOrgsRequest(ctx context.Context, r *http.Request) (*getOrgsRequest, error) {
@ -304,7 +306,7 @@ func decodeGetOrgsRequest(ctx context.Context, r *http.Request) (*getOrgsRequest
req := &getOrgsRequest{}
if orgID := qp.Get("id"); orgID != "" {
id, err := platform.IDFromString(orgID)
id, err := influxdb.IDFromString(orgID)
if err != nil {
return nil, err
}
@ -337,20 +339,20 @@ func (h *OrgHandler) handleDeleteOrg(w http.ResponseWriter, r *http.Request) {
}
type deleteOrganizationRequest struct {
OrganizationID platform.ID
OrganizationID influxdb.ID
}
func decodeDeleteOrganizationRequest(ctx context.Context, r *http.Request) (*deleteOrganizationRequest, error) {
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, &platform.Error{
Code: platform.EInvalid,
return nil, &influxdb.Error{
Code: influxdb.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
var i influxdb.ID
if err := i.DecodeFromString(id); err != nil {
return nil, err
}
@ -384,26 +386,26 @@ func (h *OrgHandler) handlePatchOrg(w http.ResponseWriter, r *http.Request) {
}
type patchOrgRequest struct {
Update platform.OrganizationUpdate
OrgID platform.ID
Update influxdb.OrganizationUpdate
OrgID influxdb.ID
}
func decodePatchOrgRequest(ctx context.Context, r *http.Request) (*patchOrgRequest, error) {
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, &platform.Error{
Code: platform.EInvalid,
return nil, &influxdb.Error{
Code: influxdb.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
var i influxdb.ID
if err := i.DecodeFromString(id); err != nil {
return nil, err
}
var upd platform.OrganizationUpdate
var upd influxdb.OrganizationUpdate
if err := json.NewDecoder(r.Body).Decode(&upd); err != nil {
return nil, err
}
@ -437,7 +439,7 @@ func (h *OrgHandler) handleGetSecrets(w http.ResponseWriter, r *http.Request) {
}
type getSecretsRequest struct {
orgID platform.ID
orgID influxdb.ID
}
func decodeGetSecretsRequest(ctx context.Context, r *http.Request) (*getSecretsRequest, error) {
@ -445,13 +447,13 @@ func decodeGetSecretsRequest(ctx context.Context, r *http.Request) (*getSecretsR
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, &platform.Error{
Code: platform.EInvalid,
return nil, &influxdb.Error{
Code: influxdb.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
var i influxdb.ID
if err := i.DecodeFromString(id); err != nil {
return nil, err
}
@ -479,7 +481,7 @@ func (h *OrgHandler) handlePatchSecrets(w http.ResponseWriter, r *http.Request)
}
type patchSecretsRequest struct {
orgID platform.ID
orgID influxdb.ID
secrets map[string]string
}
@ -488,13 +490,13 @@ func decodePatchSecretsRequest(ctx context.Context, r *http.Request) (*patchSecr
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, &platform.Error{
Code: platform.EInvalid,
return nil, &influxdb.Error{
Code: influxdb.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
var i influxdb.ID
if err := i.DecodeFromString(id); err != nil {
return nil, err
}
@ -527,7 +529,7 @@ func (h *OrgHandler) handleDeleteSecrets(w http.ResponseWriter, r *http.Request)
}
type deleteSecretsRequest struct {
orgID platform.ID
orgID influxdb.ID
secrets []string
}
@ -536,13 +538,13 @@ func decodeDeleteSecretsRequest(ctx context.Context, r *http.Request) (*deleteSe
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, &platform.Error{
Code: platform.EInvalid,
return nil, &influxdb.Error{
Code: influxdb.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
var i influxdb.ID
if err := i.DecodeFromString(id); err != nil {
return nil, err
}
@ -570,32 +572,32 @@ type OrganizationService struct {
}
// FindOrganizationByID gets a single organization with a given id using HTTP.
func (s *OrganizationService) FindOrganizationByID(ctx context.Context, id platform.ID) (*platform.Organization, error) {
filter := platform.OrganizationFilter{ID: &id}
func (s *OrganizationService) FindOrganizationByID(ctx context.Context, id influxdb.ID) (*influxdb.Organization, error) {
filter := influxdb.OrganizationFilter{ID: &id}
o, err := s.FindOrganization(ctx, filter)
if err != nil {
return nil, &platform.Error{
return nil, &influxdb.Error{
Err: err,
Op: s.OpPrefix + platform.OpFindOrganizationByID,
Op: s.OpPrefix + influxdb.OpFindOrganizationByID,
}
}
return o, nil
}
// FindOrganization gets a single organization matching the filter using HTTP.
func (s *OrganizationService) FindOrganization(ctx context.Context, filter platform.OrganizationFilter) (*platform.Organization, error) {
func (s *OrganizationService) FindOrganization(ctx context.Context, filter influxdb.OrganizationFilter) (*influxdb.Organization, error) {
os, n, err := s.FindOrganizations(ctx, filter)
if err != nil {
return nil, &platform.Error{
return nil, &influxdb.Error{
Err: err,
Op: s.OpPrefix + platform.OpFindOrganization,
Op: s.OpPrefix + influxdb.OpFindOrganization,
}
}
if n == 0 {
return nil, &platform.Error{
Code: platform.ENotFound,
Op: s.OpPrefix + platform.OpFindOrganization,
return nil, &influxdb.Error{
Code: influxdb.ENotFound,
Op: s.OpPrefix + influxdb.OpFindOrganization,
Msg: "organization not found",
}
}
@ -604,7 +606,7 @@ func (s *OrganizationService) FindOrganization(ctx context.Context, filter platf
}
// FindOrganizations returns all organizations that match the filter via HTTP.
func (s *OrganizationService) FindOrganizations(ctx context.Context, filter platform.OrganizationFilter, opt ...platform.FindOptions) ([]*platform.Organization, int, error) {
func (s *OrganizationService) FindOrganizations(ctx context.Context, filter influxdb.OrganizationFilter, opt ...influxdb.FindOptions) ([]*influxdb.Organization, int, error) {
url, err := newURL(s.Addr, organizationPath)
if err != nil {
return nil, 0, err
@ -642,16 +644,16 @@ func (s *OrganizationService) FindOrganizations(ctx context.Context, filter plat
return nil, 0, err
}
orgs := os.ToPlatform()
orgs := os.Toinfluxdb()
return orgs, len(orgs), nil
}
// CreateOrganization creates an organization.
func (s *OrganizationService) CreateOrganization(ctx context.Context, o *platform.Organization) error {
func (s *OrganizationService) CreateOrganization(ctx context.Context, o *influxdb.Organization) error {
if o.Name == "" {
return &platform.Error{
Code: platform.EInvalid,
return &influxdb.Error{
Code: influxdb.EInvalid,
Msg: "organization name is required",
}
}
@ -695,7 +697,7 @@ func (s *OrganizationService) CreateOrganization(ctx context.Context, o *platfor
}
// UpdateOrganization updates the organization over HTTP.
func (s *OrganizationService) UpdateOrganization(ctx context.Context, id platform.ID, upd platform.OrganizationUpdate) (*platform.Organization, error) {
func (s *OrganizationService) UpdateOrganization(ctx context.Context, id influxdb.ID, upd influxdb.OrganizationUpdate) (*influxdb.Organization, error) {
u, err := newURL(s.Addr, organizationIDPath(id))
if err != nil {
return nil, err
@ -726,7 +728,7 @@ func (s *OrganizationService) UpdateOrganization(ctx context.Context, id platfor
return nil, err
}
var o platform.Organization
var o influxdb.Organization
if err := json.NewDecoder(resp.Body).Decode(&o); err != nil {
return nil, err
}
@ -735,7 +737,7 @@ func (s *OrganizationService) UpdateOrganization(ctx context.Context, id platfor
}
// DeleteOrganization removes organization id over HTTP.
func (s *OrganizationService) DeleteOrganization(ctx context.Context, id platform.ID) error {
func (s *OrganizationService) DeleteOrganization(ctx context.Context, id influxdb.ID) error {
u, err := newURL(s.Addr, organizationIDPath(id))
if err != nil {
return err
@ -757,7 +759,7 @@ func (s *OrganizationService) DeleteOrganization(ctx context.Context, id platfor
return CheckErrorStatus(http.StatusNoContent, resp)
}
func organizationIDPath(id platform.ID) string {
func organizationIDPath(id influxdb.ID) string {
return path.Join(organizationPath, id.String())
}
@ -784,21 +786,21 @@ func (h *OrgHandler) handleGetOrgLog(w http.ResponseWriter, r *http.Request) {
}
type getOrganizationLogRequest struct {
OrganizationID platform.ID
opts platform.FindOptions
OrganizationID influxdb.ID
opts influxdb.FindOptions
}
func decodeGetOrganizationLogRequest(ctx context.Context, r *http.Request) (*getOrganizationLogRequest, error) {
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, &platform.Error{
Code: platform.EInvalid,
return nil, &influxdb.Error{
Code: influxdb.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
var i influxdb.ID
if err := i.DecodeFromString(id); err != nil {
return nil, err
}
@ -814,7 +816,7 @@ func decodeGetOrganizationLogRequest(ctx context.Context, r *http.Request) (*get
}, nil
}
func newOrganizationLogResponse(id platform.ID, es []*platform.OperationLogEntry) *operationLogResponse {
func newOrganizationLogResponse(id influxdb.ID, es []*influxdb.OperationLogEntry) *operationLogResponse {
log := make([]*operationLogEntryResponse, 0, len(es))
for _, e := range es {
log = append(log, newOperationLogEntryResponse(e))

View File

@ -102,6 +102,7 @@ func NewScraperHandler(b *ScraperBackend) *ScraperHandler {
labelBackend := &LabelBackend{
Logger: b.Logger.With(zap.String("handler", "label")),
LabelService: b.LabelService,
ResourceType: influxdb.ScraperResourceType,
}
h.HandlerFunc("GET", targetsIDLabelsPath, newGetLabelsHandler(labelBackend))
h.HandlerFunc("POST", targetsIDLabelsPath, newPostLabelHandler(labelBackend))

View File

@ -130,6 +130,7 @@ func NewTaskHandler(b *TaskBackend) *TaskHandler {
labelBackend := &LabelBackend{
Logger: b.Logger.With(zap.String("handler", "label")),
LabelService: b.LabelService,
ResourceType: platform.TasksResourceType,
}
h.HandlerFunc("GET", tasksIDLabelsPath, newGetLabelsHandler(labelBackend))
h.HandlerFunc("POST", tasksIDLabelsPath, newPostLabelHandler(labelBackend))

View File

@ -5,13 +5,14 @@ import (
"context"
"encoding/json"
"fmt"
"go.uber.org/zap"
"io/ioutil"
"net/http"
"net/http/httptest"
"strings"
"testing"
"go.uber.org/zap"
platform "github.com/influxdata/influxdb"
pcontext "github.com/influxdata/influxdb/context"
"github.com/influxdata/influxdb/inmem"
@ -835,3 +836,101 @@ func TestTaskUserResourceMap(t *testing.T) {
t.Fatalf("deleted resource (%s) doesn't match created resource (%s)", deletedResource, created.ResourceID)
}
}
func TestService_handlePostTaskLabel(t *testing.T) {
type fields struct {
LabelService platform.LabelService
}
type args struct {
labelMapping *platform.LabelMapping
taskID platform.ID
}
type wants struct {
statusCode int
contentType string
body string
}
tests := []struct {
name string
fields fields
args args
wants wants
}{
{
name: "add label to task",
fields: fields{
LabelService: &mock.LabelService{
FindLabelByIDFn: func(ctx context.Context, id platform.ID) (*platform.Label, error) {
return &platform.Label{
ID: 1,
Name: "label",
Properties: map[string]string{
"color": "fff000",
},
}, nil
},
CreateLabelMappingFn: func(ctx context.Context, m *platform.LabelMapping) error { return nil },
},
},
args: args{
labelMapping: &platform.LabelMapping{
ResourceID: 100,
LabelID: 1,
},
taskID: 100,
},
wants: wants{
statusCode: http.StatusCreated,
contentType: "application/json; charset=utf-8",
body: `
{
"label": {
"id": "0000000000000001",
"name": "label",
"properties": {
"color": "fff000"
}
},
"links": {
"self": "/api/v2/labels/0000000000000001"
}
}
`,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
taskBE := NewMockTaskBackend()
taskBE.LabelService = tt.fields.LabelService
h := NewTaskHandler(taskBE)
b, err := json.Marshal(tt.args.labelMapping)
if err != nil {
t.Fatalf("failed to unmarshal label mapping: %v", err)
}
url := fmt.Sprintf("http://localhost:9999/api/v2/tasks/%s/labels", tt.args.taskID)
r := httptest.NewRequest("POST", url, bytes.NewReader(b))
w := httptest.NewRecorder()
h.ServeHTTP(w, r)
res := w.Result()
content := res.Header.Get("Content-Type")
body, _ := ioutil.ReadAll(res.Body)
if res.StatusCode != tt.wants.statusCode {
t.Errorf("got %v, want %v", res.StatusCode, tt.wants.statusCode)
}
if tt.wants.contentType != "" && content != tt.wants.contentType {
t.Errorf("got %v, want %v", content, tt.wants.contentType)
}
if eq, diff, _ := jsonEqual(string(body), tt.wants.body); tt.wants.body != "" && !eq {
t.Errorf("Diff\n%s", diff)
}
})
}
}

View File

@ -105,6 +105,7 @@ func NewTelegrafHandler(b *TelegrafBackend) *TelegrafHandler {
labelBackend := &LabelBackend{
Logger: b.Logger.With(zap.String("handler", "label")),
LabelService: b.LabelService,
ResourceType: platform.TelegrafsResourceType,
}
h.HandlerFunc("GET", telegrafsIDLabelsPath, newGetLabelsHandler(labelBackend))
h.HandlerFunc("POST", telegrafsIDLabelsPath, newPostLabelHandler(labelBackend))