From 910d310c2019875eeb64fabed28b34ad7abffbde Mon Sep 17 00:00:00 2001 From: Jade McGough Date: Thu, 3 Jan 2019 11:48:26 -0800 Subject: [PATCH 1/4] feat(http): add labels to telegraf GET responses --- http/telegraf.go | 48 +++++++++++++++++++++++++++++++------------ http/telegraf_test.go | 5 +++-- 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/http/telegraf.go b/http/telegraf.go index b0507566b4..a9c364cf4f 100644 --- a/http/telegraf.go +++ b/http/telegraf.go @@ -76,34 +76,44 @@ func NewTelegrafHandler( return h } -type link struct { - Self string `json:"self"` +type telegrafLinks struct { + Self string `json:"self"` + Labels string `json:"labels"` } type telegrafResponse struct { *platform.TelegrafConfig - Links link `json:"links"` + Labels []platform.Label `json:"labels"` + Links telegrafLinks `json:"links"` } type telegrafResponses struct { TelegrafConfigs []telegrafResponse `json:"configurations"` } -func newTelegrafResponse(tc *platform.TelegrafConfig) telegrafResponse { - return telegrafResponse{ +func newTelegrafResponse(tc *platform.TelegrafConfig, labels []*platform.Label) telegrafResponse { + res := telegrafResponse{ TelegrafConfig: tc, - Links: link{ - Self: fmt.Sprintf("/api/v2/telegrafs/%s", tc.ID.String()), + Links: telegrafLinks{ + Self: fmt.Sprintf("/api/v2/telegrafs/%s", tc.ID), + Labels: fmt.Sprintf("/api/v2/telegrafs/%s/labels", tc.ID), }, } + + for _, l := range labels { + res.Labels = append(res.Labels, *l) + } + + return res } -func newTelegrafResponses(tcs []*platform.TelegrafConfig) telegrafResponses { +func newTelegrafResponses(ctx context.Context, tcs []*platform.TelegrafConfig, labelService platform.LabelService) telegrafResponses { resp := telegrafResponses{ TelegrafConfigs: make([]telegrafResponse, len(tcs)), } for i, c := range tcs { - resp.TelegrafConfigs[i] = newTelegrafResponse(c) + labels, _ := labelService.FindLabels(ctx, platform.LabelFilter{ResourceID: c.ID}) + resp.TelegrafConfigs[i] = newTelegrafResponse(c, labels) } return resp } @@ -134,7 +144,7 @@ func (h *TelegrafHandler) handleGetTelegrafs(w http.ResponseWriter, r *http.Requ EncodeError(ctx, err, w) return } - if err := encodeResponse(ctx, w, http.StatusOK, newTelegrafResponses(tcs)); err != nil { + if err := encodeResponse(ctx, w, http.StatusOK, newTelegrafResponses(ctx, tcs, h.LabelService)); err != nil { logEncodingError(h.Logger, r, err) return } @@ -163,7 +173,13 @@ func (h *TelegrafHandler) handleGetTelegraf(w http.ResponseWriter, r *http.Reque w.WriteHeader(http.StatusOK) w.Write([]byte(tc.TOML())) case "application/json": - if err := encodeResponse(ctx, w, http.StatusOK, newTelegrafResponse(tc)); err != nil { + labels, err := h.LabelService.FindLabels(ctx, platform.LabelFilter{ResourceID: tc.ID}) + if err != nil { + EncodeError(ctx, err, w) + return + } + + if err := encodeResponse(ctx, w, http.StatusOK, newTelegrafResponse(tc, labels)); err != nil { logEncodingError(h.Logger, r, err) return } @@ -241,7 +257,7 @@ func (h *TelegrafHandler) handlePostTelegraf(w http.ResponseWriter, r *http.Requ return } - if err := encodeResponse(ctx, w, http.StatusCreated, newTelegrafResponse(tc)); err != nil { + if err := encodeResponse(ctx, w, http.StatusCreated, newTelegrafResponse(tc, []*platform.Label{})); err != nil { logEncodingError(h.Logger, r, err) return } @@ -268,7 +284,13 @@ func (h *TelegrafHandler) handlePutTelegraf(w http.ResponseWriter, r *http.Reque return } - if err := encodeResponse(ctx, w, http.StatusOK, newTelegrafResponse(tc)); err != nil { + labels, err := h.LabelService.FindLabels(ctx, platform.LabelFilter{ResourceID: tc.ID}) + if err != nil { + EncodeError(ctx, err, w) + return + } + + if err := encodeResponse(ctx, w, http.StatusOK, newTelegrafResponse(tc, labels)); err != nil { logEncodingError(h.Logger, r, err) return } diff --git a/http/telegraf_test.go b/http/telegraf_test.go index 8db0c4dc9c..b3b6820b6c 100644 --- a/http/telegraf_test.go +++ b/http/telegraf_test.go @@ -724,7 +724,8 @@ func Test_newTelegrafResponses(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - res := newTelegrafResponses(tt.args.tcs) + ctx := context.Background() + res := newTelegrafResponses(ctx, tt.args.tcs, mock.NewLabelService()) got, err := json.Marshal(res) if err != nil { t.Fatalf("newTelegrafResponses() JSON marshal %v", err) @@ -802,7 +803,7 @@ func Test_newTelegrafResponse(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - res := newTelegrafResponse(tt.args.tc) + res := newTelegrafResponse(tt.args.tc, []*platform.Label{}) got, err := json.Marshal(res) if err != nil { t.Fatalf("newTelegrafResponse() JSON marshal %v", err) From 815795261da0e464f088636fc2a604676d14d87a Mon Sep 17 00:00:00 2001 From: Jade McGough Date: Thu, 3 Jan 2019 15:56:52 -0800 Subject: [PATCH 2/4] feat(http): add labels to bucket responses --- http/bucket_service.go | 44 +++++++++++++++++++++++++++++++----------- http/bucket_test.go | 42 ++++++++++++++++++++++++++-------------- http/onboarding.go | 2 +- http/swagger.yml | 8 ++++++-- http/telegraf.go | 1 + 5 files changed, 69 insertions(+), 28 deletions(-) diff --git a/http/bucket_service.go b/http/bucket_service.go index 9fce841385..1ebe05b8c3 100644 --- a/http/bucket_service.go +++ b/http/bucket_service.go @@ -188,17 +188,26 @@ func newBucketUpdate(pb *platform.BucketUpdate) *bucketUpdate { type bucketResponse struct { Links map[string]string `json:"links"` bucket + Labels []platform.Label `json:"labels"` } -func newBucketResponse(b *platform.Bucket) *bucketResponse { - return &bucketResponse{ +func newBucketResponse(b *platform.Bucket, labels []*platform.Label) *bucketResponse { + res := &bucketResponse{ Links: map[string]string{ - "self": fmt.Sprintf("/api/v2/buckets/%s", b.ID), - "log": fmt.Sprintf("/api/v2/buckets/%s/log", b.ID), - "org": fmt.Sprintf("/api/v2/orgs/%s", b.OrganizationID), + "self": fmt.Sprintf("/api/v2/buckets/%s", b.ID), + "log": fmt.Sprintf("/api/v2/buckets/%s/log", b.ID), + "labels": fmt.Sprintf("/api/v2/buckets/%s/labels", b.ID), + "org": fmt.Sprintf("/api/v2/orgs/%s", b.OrganizationID), }, bucket: *newBucket(b), + Labels: []platform.Label{}, } + + for _, l := range labels { + res.Labels = append(res.Labels, *l) + } + + return res } type bucketsResponse struct { @@ -206,10 +215,11 @@ type bucketsResponse struct { Buckets []*bucketResponse `json:"buckets"` } -func newBucketsResponse(opts platform.FindOptions, f platform.BucketFilter, bs []*platform.Bucket) *bucketsResponse { +func newBucketsResponse(ctx context.Context, opts platform.FindOptions, f platform.BucketFilter, bs []*platform.Bucket, labelService platform.LabelService) *bucketsResponse { rs := make([]*bucketResponse, 0, len(bs)) for _, b := range bs { - rs = append(rs, newBucketResponse(b)) + labels, _ := labelService.FindLabels(ctx, platform.LabelFilter{ResourceID: b.ID}) + rs = append(rs, newBucketResponse(b, labels)) } return &bucketsResponse{ Links: newPagingLinks(bucketsPath, opts, f, len(bs)), @@ -232,7 +242,7 @@ func (h *BucketHandler) handlePostBucket(w http.ResponseWriter, r *http.Request) return } - if err := encodeResponse(ctx, w, http.StatusCreated, newBucketResponse(req.Bucket)); err != nil { + if err := encodeResponse(ctx, w, http.StatusCreated, newBucketResponse(req.Bucket, []*platform.Label{})); err != nil { logEncodingError(h.Logger, r, err) return } @@ -283,7 +293,13 @@ func (h *BucketHandler) handleGetBucket(w http.ResponseWriter, r *http.Request) return } - if err := encodeResponse(ctx, w, http.StatusOK, newBucketResponse(b)); err != nil { + labels, err := h.LabelService.FindLabels(ctx, platform.LabelFilter{ResourceID: b.ID}) + if err != nil { + EncodeError(ctx, err, w) + return + } + + if err := encodeResponse(ctx, w, http.StatusOK, newBucketResponse(b, labels)); err != nil { logEncodingError(h.Logger, r, err) return } @@ -367,7 +383,7 @@ func (h *BucketHandler) handleGetBuckets(w http.ResponseWriter, r *http.Request) return } - if err := encodeResponse(ctx, w, http.StatusOK, newBucketsResponse(req.opts, req.filter, bs)); err != nil { + if err := encodeResponse(ctx, w, http.StatusOK, newBucketsResponse(ctx, req.opts, req.filter, bs, h.LabelService)); err != nil { logEncodingError(h.Logger, r, err) return } @@ -424,7 +440,13 @@ func (h *BucketHandler) handlePatchBucket(w http.ResponseWriter, r *http.Request return } - if err := encodeResponse(ctx, w, http.StatusOK, newBucketResponse(b)); err != nil { + labels, err := h.LabelService.FindLabels(ctx, platform.LabelFilter{ResourceID: b.ID}) + if err != nil { + EncodeError(ctx, err, w) + return + } + + if err := encodeResponse(ctx, w, http.StatusOK, newBucketResponse(b, labels)); err != nil { logEncodingError(h.Logger, r, err) return } diff --git a/http/bucket_test.go b/http/bucket_test.go index 3f5cc99c80..136b16c859 100644 --- a/http/bucket_test.go +++ b/http/bucket_test.go @@ -78,23 +78,27 @@ func TestService_handleGetBuckets(t *testing.T) { "links": { "org": "/api/v2/orgs/50f7ba1150f7ba11", "self": "/api/v2/buckets/0b501e7e557ab1ed", - "log": "/api/v2/buckets/0b501e7e557ab1ed/log" + "log": "/api/v2/buckets/0b501e7e557ab1ed/log", + "labels": "/api/v2/buckets/0b501e7e557ab1ed/labels" }, "id": "0b501e7e557ab1ed", "organizationID": "50f7ba1150f7ba11", "name": "hello", - "retentionRules": [{"type": "expire", "everySeconds": 2}] + "retentionRules": [{"type": "expire", "everySeconds": 2}], + "labels": [] }, { "links": { "org": "/api/v2/orgs/7e55e118dbabb1ed", "self": "/api/v2/buckets/c0175f0077a77005", - "log": "/api/v2/buckets/c0175f0077a77005/log" + "log": "/api/v2/buckets/c0175f0077a77005/log", + "labels": "/api/v2/buckets/c0175f0077a77005/labels" }, "id": "c0175f0077a77005", "organizationID": "7e55e118dbabb1ed", "name": "example", - "retentionRules": [{"type": "expire", "everySeconds": 86400}] + "retentionRules": [{"type": "expire", "everySeconds": 86400}], + "labels": [] } ] } @@ -216,12 +220,14 @@ func TestService_handleGetBucket(t *testing.T) { "links": { "org": "/api/v2/orgs/020f755c3c082000", "self": "/api/v2/buckets/020f755c3c082000", - "log": "/api/v2/buckets/020f755c3c082000/log" + "log": "/api/v2/buckets/020f755c3c082000/log", + "labels": "/api/v2/buckets/020f755c3c082000/labels" }, "id": "020f755c3c082000", "organizationID": "020f755c3c082000", "name": "hello", - "retentionRules": [{"type": "expire", "everySeconds": 30}] + "retentionRules": [{"type": "expire", "everySeconds": 30}], + "labels": [] } `, }, @@ -332,12 +338,14 @@ func TestService_handlePostBucket(t *testing.T) { "links": { "org": "/api/v2/orgs/6f626f7274697320", "self": "/api/v2/buckets/020f755c3c082000", - "log": "/api/v2/buckets/020f755c3c082000/log" + "log": "/api/v2/buckets/020f755c3c082000/log", + "labels": "/api/v2/buckets/020f755c3c082000/labels" }, "id": "020f755c3c082000", "organizationID": "6f626f7274697320", "name": "hello", - "retentionRules": [] + "retentionRules": [], + "labels": [] } `, }, @@ -542,12 +550,14 @@ func TestService_handlePatchBucket(t *testing.T) { "links": { "org": "/api/v2/orgs/020f755c3c082000", "self": "/api/v2/buckets/020f755c3c082000", - "log": "/api/v2/buckets/020f755c3c082000/log" + "log": "/api/v2/buckets/020f755c3c082000/log", + "labels": "/api/v2/buckets/020f755c3c082000/labels" }, "id": "020f755c3c082000", "organizationID": "020f755c3c082000", "name": "example", - "retentionRules": [{"type": "expire", "everySeconds": 2}] + "retentionRules": [{"type": "expire", "everySeconds": 2}], + "labels": [] } `, }, @@ -613,12 +623,14 @@ func TestService_handlePatchBucket(t *testing.T) { "links": { "org": "/api/v2/orgs/020f755c3c082000", "self": "/api/v2/buckets/020f755c3c082000", - "log": "/api/v2/buckets/020f755c3c082000/log" + "log": "/api/v2/buckets/020f755c3c082000/log", + "labels": "/api/v2/buckets/020f755c3c082000/labels" }, "id": "020f755c3c082000", "organizationID": "020f755c3c082000", "name": "bucket with no retention", - "retentionRules": [] + "retentionRules": [], + "labels": [] } `, }, @@ -665,12 +677,14 @@ func TestService_handlePatchBucket(t *testing.T) { "links": { "org": "/api/v2/orgs/020f755c3c082000", "self": "/api/v2/buckets/020f755c3c082000", - "log": "/api/v2/buckets/020f755c3c082000/log" + "log": "/api/v2/buckets/020f755c3c082000/log", + "labels": "/api/v2/buckets/020f755c3c082000/labels" }, "id": "020f755c3c082000", "organizationID": "020f755c3c082000", "name": "b1", - "retentionRules": [] + "retentionRules": [], + "labels": [] } `, }, diff --git a/http/onboarding.go b/http/onboarding.go index f04dca24b3..98d437f3be 100644 --- a/http/onboarding.go +++ b/http/onboarding.go @@ -92,7 +92,7 @@ func newOnboardingResponse(results *platform.OnboardingResults) *onboardingRespo } return &onboardingResponse{ User: newUserResponse(results.User), - Bucket: newBucketResponse(results.Bucket), + Bucket: newBucketResponse(results.Bucket, []*platform.Label{}), Organization: newOrgResponse(results.Org), Auth: newAuthResponse(results.Auth, results.Org, results.User, ps), } diff --git a/http/swagger.yml b/http/swagger.yml index cefbe7605b..3c8ba280ef 100644 --- a/http/swagger.yml +++ b/http/swagger.yml @@ -4770,6 +4770,8 @@ components: example: 86400 minimum: 1 required: [type, everySeconds] + labels: + $ref: "#/components/schemas/Labels" required: [name, retentionRules] Buckets: type: object @@ -6600,8 +6602,10 @@ components: properties: self: type: string - owners: - $ref: "#/components/schemas/Owners" + labels: + type: string + labels: + $ref: "#/components/schemas/Labels" Telegrafs: type: object properties: diff --git a/http/telegraf.go b/http/telegraf.go index a9c364cf4f..c0d339ab80 100644 --- a/http/telegraf.go +++ b/http/telegraf.go @@ -98,6 +98,7 @@ func newTelegrafResponse(tc *platform.TelegrafConfig, labels []*platform.Label) Self: fmt.Sprintf("/api/v2/telegrafs/%s", tc.ID), Labels: fmt.Sprintf("/api/v2/telegrafs/%s/labels", tc.ID), }, + Labels: []platform.Label{}, } for _, l := range labels { From a80a86c6c288cc85ecf337641dfb791ccd9a5bda Mon Sep 17 00:00:00 2001 From: Jade McGough Date: Thu, 3 Jan 2019 16:10:16 -0800 Subject: [PATCH 3/4] chore(http): add labels to bucket tests --- http/bucket_test.go | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/http/bucket_test.go b/http/bucket_test.go index 136b16c859..2aa5993f78 100644 --- a/http/bucket_test.go +++ b/http/bucket_test.go @@ -21,6 +21,7 @@ import ( func TestService_handleGetBuckets(t *testing.T) { type fields struct { BucketService platform.BucketService + LabelService platform.LabelService } type args struct { queryParams map[string][]string @@ -58,6 +59,20 @@ func TestService_handleGetBuckets(t *testing.T) { }, 2, nil }, }, + &mock.LabelService{ + FindLabelsFn: func(ctx context.Context, f platform.LabelFilter) ([]*platform.Label, error) { + labels := []*platform.Label{ + { + ResourceID: f.ResourceID, + Name: "label", + Properties: map[string]string{ + "color": "fff000", + }, + }, + } + return labels, nil + }, + }, }, args: args{ map[string][]string{ @@ -85,7 +100,15 @@ func TestService_handleGetBuckets(t *testing.T) { "organizationID": "50f7ba1150f7ba11", "name": "hello", "retentionRules": [{"type": "expire", "everySeconds": 2}], - "labels": [] + "labels": [ + { + "resourceID": "0b501e7e557ab1ed", + "name": "label", + "properties": { + "color": "fff000" + } + } + ] }, { "links": { @@ -98,7 +121,15 @@ func TestService_handleGetBuckets(t *testing.T) { "organizationID": "7e55e118dbabb1ed", "name": "example", "retentionRules": [{"type": "expire", "everySeconds": 86400}], - "labels": [] + "labels": [ + { + "resourceID": "c0175f0077a77005", + "name": "label", + "properties": { + "color": "fff000" + } + } + ] } ] } @@ -113,6 +144,7 @@ func TestService_handleGetBuckets(t *testing.T) { return []*platform.Bucket{}, 0, nil }, }, + &mock.LabelService{}, }, args: args{ map[string][]string{ @@ -136,7 +168,7 @@ func TestService_handleGetBuckets(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { mappingService := mock.NewUserResourceMappingService() - labelService := mock.NewLabelService() + labelService := tt.fields.LabelService userService := mock.NewUserService() h := NewBucketHandler(mappingService, labelService, userService) h.BucketService = tt.fields.BucketService @@ -165,8 +197,8 @@ func TestService_handleGetBuckets(t *testing.T) { if tt.wants.contentType != "" && content != tt.wants.contentType { t.Errorf("%q. handleGetBuckets() = %v, want %v", tt.name, content, tt.wants.contentType) } - if eq, diff, _ := jsonEqual(string(body), tt.wants.body); tt.wants.body != "" && !eq { - t.Errorf("%q. handleGetBuckets() = ***%s***", tt.name, diff) + if eq, diff, err := jsonEqual(string(body), tt.wants.body); err != nil || tt.wants.body != "" && !eq { + t.Errorf("%q. handleGetBuckets() = ***%v***", tt.name, diff) } }) } From 6a2554d6dbcfef34f576ae7c0a3b9848738e0b8a Mon Sep 17 00:00:00 2001 From: Jade McGough Date: Thu, 3 Jan 2019 16:46:47 -0800 Subject: [PATCH 4/4] test json formatting --- http/bucket_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/http/bucket_test.go b/http/bucket_test.go index 2aa5993f78..eac5985f45 100644 --- a/http/bucket_test.go +++ b/http/bucket_test.go @@ -121,7 +121,7 @@ func TestService_handleGetBuckets(t *testing.T) { "organizationID": "7e55e118dbabb1ed", "name": "example", "retentionRules": [{"type": "expire", "everySeconds": 86400}], - "labels": [ + "labels": [ { "resourceID": "c0175f0077a77005", "name": "label", @@ -710,7 +710,7 @@ func TestService_handlePatchBucket(t *testing.T) { "org": "/api/v2/orgs/020f755c3c082000", "self": "/api/v2/buckets/020f755c3c082000", "log": "/api/v2/buckets/020f755c3c082000/log", - "labels": "/api/v2/buckets/020f755c3c082000/labels" + "labels": "/api/v2/buckets/020f755c3c082000/labels" }, "id": "020f755c3c082000", "organizationID": "020f755c3c082000",