2018-12-03 16:07:08 +00:00
|
|
|
package http
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"net/http"
|
2019-10-28 22:19:10 +00:00
|
|
|
"net/url"
|
2018-12-03 16:07:08 +00:00
|
|
|
"path"
|
|
|
|
|
2019-11-25 14:22:19 +00:00
|
|
|
"github.com/influxdata/httprouter"
|
2020-04-03 17:39:20 +00:00
|
|
|
"github.com/influxdata/influxdb/v2"
|
2021-09-13 19:12:35 +00:00
|
|
|
"github.com/influxdata/influxdb/v2/kit/platform"
|
|
|
|
"github.com/influxdata/influxdb/v2/kit/platform/errors"
|
2020-04-03 17:39:20 +00:00
|
|
|
"github.com/influxdata/influxdb/v2/pkg/httpc"
|
2019-12-08 04:10:22 +00:00
|
|
|
"go.uber.org/zap"
|
2018-12-03 16:07:08 +00:00
|
|
|
)
|
|
|
|
|
2019-01-18 19:03:36 +00:00
|
|
|
// LabelHandler represents an HTTP API handler for labels
|
|
|
|
type LabelHandler struct {
|
|
|
|
*httprouter.Router
|
2021-03-30 18:10:02 +00:00
|
|
|
errors.HTTPErrorHandler
|
2019-12-04 23:10:23 +00:00
|
|
|
log *zap.Logger
|
2019-01-18 19:03:36 +00:00
|
|
|
|
2019-04-11 05:05:17 +00:00
|
|
|
LabelService influxdb.LabelService
|
2019-01-18 19:03:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
2019-12-09 23:54:16 +00:00
|
|
|
prefixLabels = "/api/v2/labels"
|
2019-01-18 19:03:36 +00:00
|
|
|
labelsIDPath = "/api/v2/labels/:id"
|
|
|
|
)
|
|
|
|
|
|
|
|
// NewLabelHandler returns a new instance of LabelHandler
|
2021-03-30 18:10:02 +00:00
|
|
|
func NewLabelHandler(log *zap.Logger, s influxdb.LabelService, he errors.HTTPErrorHandler) *LabelHandler {
|
2019-01-18 19:03:36 +00:00
|
|
|
h := &LabelHandler{
|
2019-06-27 01:33:20 +00:00
|
|
|
Router: NewRouter(he),
|
|
|
|
HTTPErrorHandler: he,
|
2019-12-04 23:10:23 +00:00
|
|
|
log: log,
|
2019-06-27 01:33:20 +00:00
|
|
|
LabelService: s,
|
2019-01-18 19:03:36 +00:00
|
|
|
}
|
|
|
|
|
2019-12-09 23:54:16 +00:00
|
|
|
h.HandlerFunc("POST", prefixLabels, h.handlePostLabel)
|
|
|
|
h.HandlerFunc("GET", prefixLabels, h.handleGetLabels)
|
2019-01-18 19:03:36 +00:00
|
|
|
|
|
|
|
h.HandlerFunc("GET", labelsIDPath, h.handleGetLabel)
|
|
|
|
h.HandlerFunc("PATCH", labelsIDPath, h.handlePatchLabel)
|
|
|
|
h.HandlerFunc("DELETE", labelsIDPath, h.handleDeleteLabel)
|
|
|
|
|
|
|
|
return h
|
|
|
|
}
|
|
|
|
|
2020-05-28 15:26:08 +00:00
|
|
|
func (h *LabelHandler) Prefix() string {
|
|
|
|
return prefixLabels
|
|
|
|
}
|
|
|
|
|
2019-01-18 19:03:36 +00:00
|
|
|
// handlePostLabel is the HTTP handler for the POST /api/v2/labels route.
|
|
|
|
func (h *LabelHandler) handlePostLabel(w http.ResponseWriter, r *http.Request) {
|
|
|
|
ctx := r.Context()
|
|
|
|
req, err := decodePostLabelRequest(ctx, r)
|
|
|
|
if err != nil {
|
2019-06-27 01:33:20 +00:00
|
|
|
h.HandleHTTPError(ctx, err, w)
|
2019-01-18 19:03:36 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := h.LabelService.CreateLabel(ctx, req.Label); err != nil {
|
2019-06-27 01:33:20 +00:00
|
|
|
h.HandleHTTPError(ctx, err, w)
|
2019-01-18 19:03:36 +00:00
|
|
|
return
|
|
|
|
}
|
2019-12-04 23:10:23 +00:00
|
|
|
h.log.Debug("Label created", zap.String("label", fmt.Sprint(req.Label)))
|
2019-01-18 19:03:36 +00:00
|
|
|
if err := encodeResponse(ctx, w, http.StatusCreated, newLabelResponse(req.Label)); err != nil {
|
2019-12-04 23:10:23 +00:00
|
|
|
logEncodingError(h.log, r, err)
|
2019-01-18 19:03:36 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type postLabelRequest struct {
|
2019-04-11 05:05:17 +00:00
|
|
|
Label *influxdb.Label
|
2019-01-18 19:03:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (b postLabelRequest) Validate() error {
|
|
|
|
if b.Label.Name == "" {
|
2021-03-30 18:10:02 +00:00
|
|
|
return &errors.Error{
|
|
|
|
Code: errors.EInvalid,
|
2019-01-18 19:03:36 +00:00
|
|
|
Msg: "label requires a name",
|
|
|
|
}
|
|
|
|
}
|
2019-04-11 22:50:02 +00:00
|
|
|
if !b.Label.OrgID.Valid() {
|
2021-03-30 18:10:02 +00:00
|
|
|
return &errors.Error{
|
|
|
|
Code: errors.EInvalid,
|
2019-03-19 08:56:55 +00:00
|
|
|
Msg: "label requires a valid orgID",
|
|
|
|
}
|
|
|
|
}
|
2019-01-18 19:03:36 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-03-19 08:56:55 +00:00
|
|
|
// TODO(jm): ensure that the specified org actually exists
|
2019-01-18 19:03:36 +00:00
|
|
|
func decodePostLabelRequest(ctx context.Context, r *http.Request) (*postLabelRequest, error) {
|
2019-04-11 05:05:17 +00:00
|
|
|
l := &influxdb.Label{}
|
2019-01-18 19:03:36 +00:00
|
|
|
if err := json.NewDecoder(r.Body).Decode(l); err != nil {
|
2021-03-30 18:10:02 +00:00
|
|
|
return nil, &errors.Error{
|
|
|
|
Code: errors.EInvalid,
|
2019-01-18 19:03:36 +00:00
|
|
|
Msg: "unable to decode label request",
|
|
|
|
Err: err,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
req := &postLabelRequest{
|
|
|
|
Label: l,
|
|
|
|
}
|
|
|
|
|
|
|
|
return req, req.Validate()
|
|
|
|
}
|
|
|
|
|
|
|
|
// handleGetLabels is the HTTP handler for the GET /api/v2/labels route.
|
|
|
|
func (h *LabelHandler) handleGetLabels(w http.ResponseWriter, r *http.Request) {
|
|
|
|
ctx := r.Context()
|
2019-10-28 22:19:10 +00:00
|
|
|
req, err := decodeGetLabelsRequest(r.URL.Query())
|
2019-04-11 05:05:17 +00:00
|
|
|
if err != nil {
|
2019-06-27 01:33:20 +00:00
|
|
|
h.HandleHTTPError(ctx, err, w)
|
2019-04-11 05:05:17 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
labels, err := h.LabelService.FindLabels(ctx, req.filter)
|
2019-01-18 19:03:36 +00:00
|
|
|
if err != nil {
|
2019-06-27 01:33:20 +00:00
|
|
|
h.HandleHTTPError(ctx, err, w)
|
2019-01-18 19:03:36 +00:00
|
|
|
return
|
|
|
|
}
|
2020-11-11 18:54:21 +00:00
|
|
|
h.log.Debug("Labels retrieved", zap.String("labels", fmt.Sprint(labels)))
|
2019-01-18 19:03:36 +00:00
|
|
|
err = encodeResponse(ctx, w, http.StatusOK, newLabelsResponse(labels))
|
|
|
|
if err != nil {
|
2019-06-27 01:33:20 +00:00
|
|
|
h.HandleHTTPError(ctx, err, w)
|
2019-01-18 19:03:36 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-11 05:05:17 +00:00
|
|
|
type getLabelsRequest struct {
|
|
|
|
filter influxdb.LabelFilter
|
|
|
|
}
|
|
|
|
|
2019-10-28 22:19:10 +00:00
|
|
|
func decodeGetLabelsRequest(qp url.Values) (*getLabelsRequest, error) {
|
|
|
|
req := &getLabelsRequest{
|
|
|
|
filter: influxdb.LabelFilter{
|
|
|
|
Name: qp.Get("name"),
|
|
|
|
},
|
|
|
|
}
|
2019-04-11 05:05:17 +00:00
|
|
|
|
|
|
|
if orgID := qp.Get("orgID"); orgID != "" {
|
2021-03-30 18:10:02 +00:00
|
|
|
id, err := platform.IDFromString(orgID)
|
2019-04-11 05:05:17 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
req.filter.OrgID = id
|
|
|
|
}
|
|
|
|
|
|
|
|
return req, nil
|
|
|
|
}
|
|
|
|
|
2019-01-18 19:03:36 +00:00
|
|
|
// handleGetLabel is the HTTP handler for the GET /api/v2/labels/id route.
|
|
|
|
func (h *LabelHandler) handleGetLabel(w http.ResponseWriter, r *http.Request) {
|
|
|
|
ctx := r.Context()
|
|
|
|
req, err := decodeGetLabelRequest(ctx, r)
|
|
|
|
if err != nil {
|
2019-06-27 01:33:20 +00:00
|
|
|
h.HandleHTTPError(ctx, err, w)
|
2019-01-18 19:03:36 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
l, err := h.LabelService.FindLabelByID(ctx, req.LabelID)
|
|
|
|
if err != nil {
|
2019-06-27 01:33:20 +00:00
|
|
|
h.HandleHTTPError(ctx, err, w)
|
2019-01-18 19:03:36 +00:00
|
|
|
return
|
|
|
|
}
|
2019-12-04 23:10:23 +00:00
|
|
|
h.log.Debug("Label retrieved", zap.String("label", fmt.Sprint(l)))
|
2019-01-18 19:03:36 +00:00
|
|
|
if err := encodeResponse(ctx, w, http.StatusOK, newLabelResponse(l)); err != nil {
|
2019-12-04 23:10:23 +00:00
|
|
|
logEncodingError(h.log, r, err)
|
2019-01-18 19:03:36 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type getLabelRequest struct {
|
2021-03-30 18:10:02 +00:00
|
|
|
LabelID platform.ID
|
2019-01-18 19:03:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func decodeGetLabelRequest(ctx context.Context, r *http.Request) (*getLabelRequest, error) {
|
|
|
|
params := httprouter.ParamsFromContext(ctx)
|
|
|
|
id := params.ByName("id")
|
|
|
|
if id == "" {
|
2021-03-30 18:10:02 +00:00
|
|
|
return nil, &errors.Error{
|
|
|
|
Code: errors.EInvalid,
|
2019-01-18 19:03:36 +00:00
|
|
|
Msg: "label id is not valid",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-30 18:10:02 +00:00
|
|
|
var i platform.ID
|
2019-01-18 19:03:36 +00:00
|
|
|
if err := i.DecodeFromString(id); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
req := &getLabelRequest{
|
|
|
|
LabelID: i,
|
|
|
|
}
|
|
|
|
|
|
|
|
return req, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// handleDeleteLabel is the HTTP handler for the DELETE /api/v2/labels/:id route.
|
|
|
|
func (h *LabelHandler) handleDeleteLabel(w http.ResponseWriter, r *http.Request) {
|
|
|
|
ctx := r.Context()
|
|
|
|
req, err := decodeDeleteLabelRequest(ctx, r)
|
|
|
|
if err != nil {
|
2019-06-27 01:33:20 +00:00
|
|
|
h.HandleHTTPError(ctx, err, w)
|
2019-01-18 19:03:36 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := h.LabelService.DeleteLabel(ctx, req.LabelID); err != nil {
|
2019-06-27 01:33:20 +00:00
|
|
|
h.HandleHTTPError(ctx, err, w)
|
2019-01-18 19:03:36 +00:00
|
|
|
return
|
|
|
|
}
|
2019-12-04 23:10:23 +00:00
|
|
|
h.log.Debug("Label deleted", zap.String("labelID", fmt.Sprint(req.LabelID)))
|
2019-01-18 19:03:36 +00:00
|
|
|
w.WriteHeader(http.StatusNoContent)
|
|
|
|
}
|
|
|
|
|
|
|
|
type deleteLabelRequest struct {
|
2021-03-30 18:10:02 +00:00
|
|
|
LabelID platform.ID
|
2019-01-18 19:03:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func decodeDeleteLabelRequest(ctx context.Context, r *http.Request) (*deleteLabelRequest, error) {
|
|
|
|
params := httprouter.ParamsFromContext(ctx)
|
|
|
|
id := params.ByName("id")
|
|
|
|
if id == "" {
|
2021-03-30 18:10:02 +00:00
|
|
|
return nil, &errors.Error{
|
|
|
|
Code: errors.EInvalid,
|
2019-01-24 00:15:42 +00:00
|
|
|
Msg: "url missing id",
|
|
|
|
}
|
2019-01-18 19:03:36 +00:00
|
|
|
}
|
|
|
|
|
2021-03-30 18:10:02 +00:00
|
|
|
var i platform.ID
|
2019-01-18 19:03:36 +00:00
|
|
|
if err := i.DecodeFromString(id); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
req := &deleteLabelRequest{
|
|
|
|
LabelID: i,
|
|
|
|
}
|
|
|
|
|
|
|
|
return req, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// handlePatchLabel is the HTTP handler for the PATCH /api/v2/labels route.
|
|
|
|
func (h *LabelHandler) handlePatchLabel(w http.ResponseWriter, r *http.Request) {
|
|
|
|
ctx := r.Context()
|
|
|
|
req, err := decodePatchLabelRequest(ctx, r)
|
|
|
|
if err != nil {
|
2019-06-27 01:33:20 +00:00
|
|
|
h.HandleHTTPError(ctx, err, w)
|
2019-01-18 19:03:36 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
l, err := h.LabelService.UpdateLabel(ctx, req.LabelID, req.Update)
|
|
|
|
if err != nil {
|
2019-06-27 01:33:20 +00:00
|
|
|
h.HandleHTTPError(ctx, err, w)
|
2019-01-18 19:03:36 +00:00
|
|
|
return
|
|
|
|
}
|
2019-12-04 23:10:23 +00:00
|
|
|
h.log.Debug("Label updated", zap.String("label", fmt.Sprint(l)))
|
2019-01-18 19:03:36 +00:00
|
|
|
if err := encodeResponse(ctx, w, http.StatusOK, newLabelResponse(l)); err != nil {
|
2019-12-04 23:10:23 +00:00
|
|
|
logEncodingError(h.log, r, err)
|
2019-01-18 19:03:36 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type patchLabelRequest struct {
|
2019-04-11 05:05:17 +00:00
|
|
|
Update influxdb.LabelUpdate
|
2021-03-30 18:10:02 +00:00
|
|
|
LabelID platform.ID
|
2019-01-18 19:03:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func decodePatchLabelRequest(ctx context.Context, r *http.Request) (*patchLabelRequest, error) {
|
|
|
|
params := httprouter.ParamsFromContext(ctx)
|
|
|
|
id := params.ByName("id")
|
|
|
|
if id == "" {
|
2021-03-30 18:10:02 +00:00
|
|
|
return nil, &errors.Error{
|
|
|
|
Code: errors.EInvalid,
|
2019-01-24 00:15:42 +00:00
|
|
|
Msg: "url missing id",
|
|
|
|
}
|
2019-01-18 19:03:36 +00:00
|
|
|
}
|
|
|
|
|
2021-03-30 18:10:02 +00:00
|
|
|
var i platform.ID
|
2019-01-18 19:03:36 +00:00
|
|
|
if err := i.DecodeFromString(id); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2019-04-11 05:05:17 +00:00
|
|
|
upd := &influxdb.LabelUpdate{}
|
2019-01-18 19:03:36 +00:00
|
|
|
if err := json.NewDecoder(r.Body).Decode(upd); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &patchLabelRequest{
|
|
|
|
Update: *upd,
|
|
|
|
LabelID: i,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2018-12-03 16:07:08 +00:00
|
|
|
type labelResponse struct {
|
|
|
|
Links map[string]string `json:"links"`
|
2019-04-11 05:05:17 +00:00
|
|
|
Label influxdb.Label `json:"label"`
|
2018-12-03 16:07:08 +00:00
|
|
|
}
|
|
|
|
|
2019-04-11 05:05:17 +00:00
|
|
|
func newLabelResponse(l *influxdb.Label) *labelResponse {
|
2018-12-03 16:07:08 +00:00
|
|
|
return &labelResponse{
|
|
|
|
Links: map[string]string{
|
2019-01-18 19:03:36 +00:00
|
|
|
"self": fmt.Sprintf("/api/v2/labels/%s", l.ID),
|
2018-12-03 16:07:08 +00:00
|
|
|
},
|
2018-12-18 11:51:10 +00:00
|
|
|
Label: *l,
|
2018-12-03 16:07:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type labelsResponse struct {
|
|
|
|
Links map[string]string `json:"links"`
|
2019-04-11 05:05:17 +00:00
|
|
|
Labels []*influxdb.Label `json:"labels"`
|
2018-12-03 16:07:08 +00:00
|
|
|
}
|
|
|
|
|
2019-04-11 05:05:17 +00:00
|
|
|
func newLabelsResponse(ls []*influxdb.Label) *labelsResponse {
|
2018-12-03 16:07:08 +00:00
|
|
|
return &labelsResponse{
|
|
|
|
Links: map[string]string{
|
2020-06-26 23:54:09 +00:00
|
|
|
"self": "/api/v2/labels",
|
2018-12-03 16:07:08 +00:00
|
|
|
},
|
2018-12-18 11:51:10 +00:00
|
|
|
Labels: ls,
|
2018-12-03 16:07:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-17 04:33:09 +00:00
|
|
|
// LabelBackend is all services and associated parameters required to construct
|
|
|
|
// label handlers.
|
|
|
|
type LabelBackend struct {
|
2019-12-04 23:10:23 +00:00
|
|
|
log *zap.Logger
|
2021-03-30 18:10:02 +00:00
|
|
|
errors.HTTPErrorHandler
|
2019-04-11 05:05:17 +00:00
|
|
|
LabelService influxdb.LabelService
|
|
|
|
ResourceType influxdb.ResourceType
|
2019-01-17 04:33:09 +00:00
|
|
|
}
|
|
|
|
|
2018-12-03 16:07:08 +00:00
|
|
|
// newGetLabelsHandler returns a handler func for a GET to /labels endpoints
|
2019-01-17 04:33:09 +00:00
|
|
|
func newGetLabelsHandler(b *LabelBackend) http.HandlerFunc {
|
2018-12-03 16:07:08 +00:00
|
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
ctx := r.Context()
|
|
|
|
|
2019-10-28 22:19:10 +00:00
|
|
|
req, err := decodeGetLabelMappingsRequest(ctx, b.ResourceType)
|
2018-12-03 16:07:08 +00:00
|
|
|
if err != nil {
|
2019-06-27 01:33:20 +00:00
|
|
|
b.HandleHTTPError(ctx, err, w)
|
2018-12-03 16:07:08 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-01-17 04:33:09 +00:00
|
|
|
labels, err := b.LabelService.FindResourceLabels(ctx, req.filter)
|
2018-12-03 16:07:08 +00:00
|
|
|
if err != nil {
|
2019-06-27 01:33:20 +00:00
|
|
|
b.HandleHTTPError(ctx, err, w)
|
2018-12-03 16:07:08 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-01-18 19:03:36 +00:00
|
|
|
if err := encodeResponse(ctx, w, http.StatusOK, newLabelsResponse(labels)); err != nil {
|
2019-12-04 23:10:23 +00:00
|
|
|
logEncodingError(b.log, r, err)
|
2018-12-03 16:07:08 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-11 05:05:17 +00:00
|
|
|
type getLabelMappingsRequest struct {
|
|
|
|
filter influxdb.LabelMappingFilter
|
2018-12-03 16:07:08 +00:00
|
|
|
}
|
|
|
|
|
2019-10-28 22:19:10 +00:00
|
|
|
func decodeGetLabelMappingsRequest(ctx context.Context, rt influxdb.ResourceType) (*getLabelMappingsRequest, error) {
|
2019-04-11 22:50:02 +00:00
|
|
|
req := &getLabelMappingsRequest{}
|
2018-12-03 16:07:08 +00:00
|
|
|
|
|
|
|
params := httprouter.ParamsFromContext(ctx)
|
|
|
|
id := params.ByName("id")
|
|
|
|
if id == "" {
|
2021-03-30 18:10:02 +00:00
|
|
|
return nil, &errors.Error{
|
|
|
|
Code: errors.EInvalid,
|
2019-01-24 00:15:42 +00:00
|
|
|
Msg: "url missing id",
|
|
|
|
}
|
2018-12-03 16:07:08 +00:00
|
|
|
}
|
|
|
|
|
2021-03-30 18:10:02 +00:00
|
|
|
var i platform.ID
|
2018-12-03 16:07:08 +00:00
|
|
|
if err := i.DecodeFromString(id); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
req.filter.ResourceID = i
|
2019-02-07 23:23:15 +00:00
|
|
|
req.filter.ResourceType = rt
|
2018-12-03 16:07:08 +00:00
|
|
|
|
|
|
|
return req, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// newPostLabelHandler returns a handler func for a POST to /labels endpoints
|
2019-01-17 04:33:09 +00:00
|
|
|
func newPostLabelHandler(b *LabelBackend) http.HandlerFunc {
|
2018-12-03 16:07:08 +00:00
|
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
ctx := r.Context()
|
|
|
|
|
2019-02-07 23:23:15 +00:00
|
|
|
req, err := decodePostLabelMappingRequest(ctx, r, b.ResourceType)
|
2018-12-03 16:07:08 +00:00
|
|
|
if err != nil {
|
2019-06-27 01:33:20 +00:00
|
|
|
b.HandleHTTPError(ctx, err, w)
|
2018-12-03 16:07:08 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-01-18 19:03:36 +00:00
|
|
|
if err := req.Mapping.Validate(); err != nil {
|
2019-06-27 01:33:20 +00:00
|
|
|
b.HandleHTTPError(ctx, err, w)
|
2018-12-03 16:07:08 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-01-17 04:33:09 +00:00
|
|
|
if err := b.LabelService.CreateLabelMapping(ctx, &req.Mapping); err != nil {
|
2019-06-27 01:33:20 +00:00
|
|
|
b.HandleHTTPError(ctx, err, w)
|
2018-12-03 16:07:08 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-01-17 04:33:09 +00:00
|
|
|
label, err := b.LabelService.FindLabelByID(ctx, req.Mapping.LabelID)
|
2019-01-18 19:03:36 +00:00
|
|
|
if err != nil {
|
2019-06-27 01:33:20 +00:00
|
|
|
b.HandleHTTPError(ctx, err, w)
|
2019-01-18 19:03:36 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := encodeResponse(ctx, w, http.StatusCreated, newLabelResponse(label)); err != nil {
|
2019-12-04 23:10:23 +00:00
|
|
|
logEncodingError(b.log, r, err)
|
2018-12-03 16:07:08 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-18 19:03:36 +00:00
|
|
|
type postLabelMappingRequest struct {
|
2019-04-11 05:05:17 +00:00
|
|
|
Mapping influxdb.LabelMapping
|
2018-12-03 16:07:08 +00:00
|
|
|
}
|
|
|
|
|
2019-04-11 05:05:17 +00:00
|
|
|
func decodePostLabelMappingRequest(ctx context.Context, r *http.Request, rt influxdb.ResourceType) (*postLabelMappingRequest, error) {
|
2018-12-03 16:07:08 +00:00
|
|
|
params := httprouter.ParamsFromContext(ctx)
|
|
|
|
id := params.ByName("id")
|
|
|
|
if id == "" {
|
2021-03-30 18:10:02 +00:00
|
|
|
return nil, &errors.Error{
|
|
|
|
Code: errors.EInvalid,
|
2019-01-24 00:15:42 +00:00
|
|
|
Msg: "url missing id",
|
|
|
|
}
|
2018-12-03 16:07:08 +00:00
|
|
|
}
|
|
|
|
|
2021-03-30 18:10:02 +00:00
|
|
|
var rid platform.ID
|
2018-12-03 16:07:08 +00:00
|
|
|
if err := rid.DecodeFromString(id); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2019-04-11 05:05:17 +00:00
|
|
|
mapping := &influxdb.LabelMapping{}
|
2019-01-18 19:03:36 +00:00
|
|
|
if err := json.NewDecoder(r.Body).Decode(mapping); err != nil {
|
2021-03-30 18:10:02 +00:00
|
|
|
return nil, &errors.Error{
|
|
|
|
Code: errors.EInvalid,
|
2019-03-29 15:52:06 +00:00
|
|
|
Msg: "Invalid post label map request",
|
|
|
|
}
|
2019-01-02 19:17:28 +00:00
|
|
|
}
|
|
|
|
|
2019-01-22 17:55:04 +00:00
|
|
|
mapping.ResourceID = rid
|
2019-02-07 23:23:15 +00:00
|
|
|
mapping.ResourceType = rt
|
2019-01-02 19:17:28 +00:00
|
|
|
|
2019-01-18 19:03:36 +00:00
|
|
|
if err := mapping.Validate(); err != nil {
|
2019-01-02 19:17:28 +00:00
|
|
|
return nil, err
|
2018-12-03 16:07:08 +00:00
|
|
|
}
|
|
|
|
|
2019-01-18 19:03:36 +00:00
|
|
|
req := &postLabelMappingRequest{
|
|
|
|
Mapping: *mapping,
|
2019-01-02 19:17:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return req, nil
|
2018-12-03 16:07:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// newDeleteLabelHandler returns a handler func for a DELETE to /labels endpoints
|
2019-01-17 04:33:09 +00:00
|
|
|
func newDeleteLabelHandler(b *LabelBackend) http.HandlerFunc {
|
2018-12-03 16:07:08 +00:00
|
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
ctx := r.Context()
|
|
|
|
|
2019-01-18 19:03:36 +00:00
|
|
|
req, err := decodeDeleteLabelMappingRequest(ctx, r)
|
2018-12-03 16:07:08 +00:00
|
|
|
if err != nil {
|
2019-06-27 01:33:20 +00:00
|
|
|
b.HandleHTTPError(ctx, err, w)
|
2018-12-03 16:07:08 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-04-11 05:05:17 +00:00
|
|
|
mapping := &influxdb.LabelMapping{
|
2019-02-07 23:23:15 +00:00
|
|
|
LabelID: req.LabelID,
|
|
|
|
ResourceID: req.ResourceID,
|
|
|
|
ResourceType: b.ResourceType,
|
2018-12-03 16:07:08 +00:00
|
|
|
}
|
|
|
|
|
2019-01-17 04:33:09 +00:00
|
|
|
if err := b.LabelService.DeleteLabelMapping(ctx, mapping); err != nil {
|
2019-06-27 01:33:20 +00:00
|
|
|
b.HandleHTTPError(ctx, err, w)
|
2018-12-03 16:07:08 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
w.WriteHeader(http.StatusNoContent)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-18 19:03:36 +00:00
|
|
|
type deleteLabelMappingRequest struct {
|
2021-03-30 18:10:02 +00:00
|
|
|
ResourceID platform.ID
|
|
|
|
LabelID platform.ID
|
2018-12-03 16:07:08 +00:00
|
|
|
}
|
|
|
|
|
2019-01-18 19:03:36 +00:00
|
|
|
func decodeDeleteLabelMappingRequest(ctx context.Context, r *http.Request) (*deleteLabelMappingRequest, error) {
|
2018-12-03 16:07:08 +00:00
|
|
|
params := httprouter.ParamsFromContext(ctx)
|
|
|
|
id := params.ByName("id")
|
|
|
|
if id == "" {
|
2021-03-30 18:10:02 +00:00
|
|
|
return nil, &errors.Error{
|
|
|
|
Code: errors.EInvalid,
|
2018-12-18 17:14:59 +00:00
|
|
|
Msg: "url missing resource id",
|
|
|
|
}
|
2018-12-03 16:07:08 +00:00
|
|
|
}
|
|
|
|
|
2021-03-30 18:10:02 +00:00
|
|
|
var rid platform.ID
|
2019-01-18 19:03:36 +00:00
|
|
|
if err := rid.DecodeFromString(id); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
id = params.ByName("lid")
|
|
|
|
if id == "" {
|
2021-03-30 18:10:02 +00:00
|
|
|
return nil, &errors.Error{
|
|
|
|
Code: errors.EInvalid,
|
2019-01-18 19:03:36 +00:00
|
|
|
Msg: "label id is missing",
|
2018-12-18 17:14:59 +00:00
|
|
|
}
|
2018-12-03 16:07:08 +00:00
|
|
|
}
|
|
|
|
|
2021-03-30 18:10:02 +00:00
|
|
|
var lid platform.ID
|
2019-01-18 19:03:36 +00:00
|
|
|
if err := lid.DecodeFromString(id); err != nil {
|
2018-12-03 16:07:08 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2019-01-18 19:03:36 +00:00
|
|
|
return &deleteLabelMappingRequest{
|
|
|
|
LabelID: lid,
|
2018-12-18 09:38:49 +00:00
|
|
|
ResourceID: rid,
|
|
|
|
}, nil
|
2018-12-03 16:07:08 +00:00
|
|
|
}
|
|
|
|
|
2021-03-30 18:10:02 +00:00
|
|
|
func labelIDPath(id platform.ID) string {
|
2019-12-09 23:54:16 +00:00
|
|
|
return path.Join(prefixLabels, id.String())
|
2019-01-18 19:03:36 +00:00
|
|
|
}
|
|
|
|
|
2019-12-07 18:54:03 +00:00
|
|
|
// LabelService connects to Influx via HTTP using tokens to manage labels
|
|
|
|
type LabelService struct {
|
2019-12-08 04:10:22 +00:00
|
|
|
Client *httpc.Client
|
2019-12-07 18:54:03 +00:00
|
|
|
OpPrefix string
|
|
|
|
}
|
|
|
|
|
2019-01-18 19:03:36 +00:00
|
|
|
// FindLabelByID returns a single label by ID.
|
2021-03-30 18:10:02 +00:00
|
|
|
func (s *LabelService) FindLabelByID(ctx context.Context, id platform.ID) (*influxdb.Label, error) {
|
2019-01-18 19:03:36 +00:00
|
|
|
var lr labelResponse
|
2019-12-08 04:10:22 +00:00
|
|
|
err := s.Client.
|
|
|
|
Get(labelIDPath(id)).
|
2019-12-07 18:54:03 +00:00
|
|
|
DecodeJSON(&lr).
|
|
|
|
Do(ctx)
|
|
|
|
if err != nil {
|
2019-01-18 19:03:36 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &lr.Label, nil
|
|
|
|
}
|
|
|
|
|
2019-10-28 22:19:10 +00:00
|
|
|
// FindLabels is a client for the find labels response from the server.
|
2019-04-11 05:05:17 +00:00
|
|
|
func (s *LabelService) FindLabels(ctx context.Context, filter influxdb.LabelFilter, opt ...influxdb.FindOptions) ([]*influxdb.Label, error) {
|
2020-04-30 14:52:21 +00:00
|
|
|
params := influxdb.FindOptionParams(opt...)
|
2019-10-28 22:19:10 +00:00
|
|
|
if filter.OrgID != nil {
|
2019-12-10 03:11:53 +00:00
|
|
|
params = append(params, [2]string{"orgID", filter.OrgID.String()})
|
2019-10-28 22:19:10 +00:00
|
|
|
}
|
|
|
|
if filter.Name != "" {
|
2019-12-10 03:11:53 +00:00
|
|
|
params = append(params, [2]string{"name", filter.Name})
|
2019-10-28 22:19:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var lr labelsResponse
|
2019-12-08 04:10:22 +00:00
|
|
|
err := s.Client.
|
2019-12-09 23:54:16 +00:00
|
|
|
Get(prefixLabels).
|
2019-12-10 03:11:53 +00:00
|
|
|
QueryParams(params...).
|
2019-12-07 18:54:03 +00:00
|
|
|
DecodeJSON(&lr).
|
|
|
|
Do(ctx)
|
|
|
|
if err != nil {
|
2019-10-28 22:19:10 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return lr.Labels, nil
|
2019-01-18 19:03:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// FindResourceLabels returns a list of labels, derived from a label mapping filter.
|
2019-04-11 05:05:17 +00:00
|
|
|
func (s *LabelService) FindResourceLabels(ctx context.Context, filter influxdb.LabelMappingFilter) ([]*influxdb.Label, error) {
|
2019-09-13 17:12:07 +00:00
|
|
|
if err := filter.Valid(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-12-03 16:07:08 +00:00
|
|
|
|
|
|
|
var r labelsResponse
|
2019-12-08 04:10:22 +00:00
|
|
|
err := s.Client.
|
|
|
|
Get(resourceIDPath(filter.ResourceType, filter.ResourceID, "labels")).
|
2019-12-07 18:54:03 +00:00
|
|
|
DecodeJSON(&r).
|
|
|
|
Do(ctx)
|
|
|
|
if err != nil {
|
2018-12-03 16:07:08 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
2018-12-18 11:51:10 +00:00
|
|
|
return r.Labels, nil
|
2018-12-03 16:07:08 +00:00
|
|
|
}
|
|
|
|
|
2019-01-18 19:03:36 +00:00
|
|
|
// CreateLabel creates a new label.
|
2019-04-11 05:05:17 +00:00
|
|
|
func (s *LabelService) CreateLabel(ctx context.Context, l *influxdb.Label) error {
|
2019-01-18 19:03:36 +00:00
|
|
|
var lr labelResponse
|
2019-12-08 04:10:22 +00:00
|
|
|
err := s.Client.
|
2019-12-12 03:26:02 +00:00
|
|
|
PostJSON(l, prefixLabels).
|
2019-12-07 18:54:03 +00:00
|
|
|
DecodeJSON(&lr).
|
|
|
|
Do(ctx)
|
|
|
|
if err != nil {
|
2019-01-18 19:03:36 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-10-24 23:59:01 +00:00
|
|
|
// this is super dirty >_<
|
|
|
|
*l = lr.Label
|
2019-01-18 19:03:36 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// UpdateLabel updates a label and returns the updated label.
|
2021-03-30 18:10:02 +00:00
|
|
|
func (s *LabelService) UpdateLabel(ctx context.Context, id platform.ID, upd influxdb.LabelUpdate) (*influxdb.Label, error) {
|
2019-01-18 19:03:36 +00:00
|
|
|
var lr labelResponse
|
2019-12-08 04:10:22 +00:00
|
|
|
err := s.Client.
|
2019-12-12 03:26:02 +00:00
|
|
|
PatchJSON(upd, labelIDPath(id)).
|
2019-12-07 18:54:03 +00:00
|
|
|
DecodeJSON(&lr).
|
|
|
|
Do(ctx)
|
|
|
|
if err != nil {
|
2019-01-18 19:03:36 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &lr.Label, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// DeleteLabel removes a label by ID.
|
2021-03-30 18:10:02 +00:00
|
|
|
func (s *LabelService) DeleteLabel(ctx context.Context, id platform.ID) error {
|
2019-12-08 04:10:22 +00:00
|
|
|
return s.Client.
|
|
|
|
Delete(labelIDPath(id)).
|
|
|
|
Do(ctx)
|
2019-12-07 18:54:03 +00:00
|
|
|
}
|
2019-01-18 19:03:36 +00:00
|
|
|
|
2019-12-07 18:54:03 +00:00
|
|
|
// CreateLabelMapping will create a labbel mapping
|
|
|
|
func (s *LabelService) CreateLabelMapping(ctx context.Context, m *influxdb.LabelMapping) error {
|
|
|
|
if err := m.Validate(); err != nil {
|
2019-01-18 19:03:36 +00:00
|
|
|
return err
|
|
|
|
}
|
2019-01-18 22:32:53 +00:00
|
|
|
|
2019-12-07 18:54:03 +00:00
|
|
|
urlPath := resourceIDPath(m.ResourceType, m.ResourceID, "labels")
|
2019-12-08 04:10:22 +00:00
|
|
|
return s.Client.
|
2019-12-12 03:26:02 +00:00
|
|
|
PostJSON(m, urlPath).
|
2019-12-07 18:54:03 +00:00
|
|
|
DecodeJSON(m).
|
|
|
|
Do(ctx)
|
2019-01-18 19:03:36 +00:00
|
|
|
}
|
|
|
|
|
2019-04-11 05:05:17 +00:00
|
|
|
func (s *LabelService) DeleteLabelMapping(ctx context.Context, m *influxdb.LabelMapping) error {
|
2019-12-07 18:54:03 +00:00
|
|
|
if err := m.Validate(); err != nil {
|
2018-12-03 16:07:08 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-12-08 04:10:22 +00:00
|
|
|
return s.Client.
|
refactor(kv): delete deprecated kv service code
This includes removal of a lot of kv.Service responsibilities. However,
it does not finish the re-wiring. It removes documents, telegrafs,
notification rules + endpoints, checks, orgs, users, buckets, passwords,
urms, labels and authorizations. There are some oustanding pieces that
are needed to get kv service compiling (dashboard service urm
dependency). Then all the call sites for kv service need updating and
the new implementations of telegraf and notification rules + endpoints
needed installing (along with any necessary migrations).
2020-10-20 13:25:36 +00:00
|
|
|
Delete(resourceIDMappingPath(m.ResourceType, m.ResourceID, "labels", m.LabelID)).
|
2019-12-08 04:10:22 +00:00
|
|
|
Do(ctx)
|
2018-12-03 16:07:08 +00:00
|
|
|
}
|
refactor(kv): delete deprecated kv service code
This includes removal of a lot of kv.Service responsibilities. However,
it does not finish the re-wiring. It removes documents, telegrafs,
notification rules + endpoints, checks, orgs, users, buckets, passwords,
urms, labels and authorizations. There are some oustanding pieces that
are needed to get kv service compiling (dashboard service urm
dependency). Then all the call sites for kv service need updating and
the new implementations of telegraf and notification rules + endpoints
needed installing (along with any necessary migrations).
2020-10-20 13:25:36 +00:00
|
|
|
|
2021-03-30 18:10:02 +00:00
|
|
|
func resourceIDMappingPath(resourceType influxdb.ResourceType, resourceID platform.ID, p string, labelID platform.ID) string {
|
refactor(kv): delete deprecated kv service code
This includes removal of a lot of kv.Service responsibilities. However,
it does not finish the re-wiring. It removes documents, telegrafs,
notification rules + endpoints, checks, orgs, users, buckets, passwords,
urms, labels and authorizations. There are some oustanding pieces that
are needed to get kv service compiling (dashboard service urm
dependency). Then all the call sites for kv service need updating and
the new implementations of telegraf and notification rules + endpoints
needed installing (along with any necessary migrations).
2020-10-20 13:25:36 +00:00
|
|
|
return path.Join("/api/v2/", string(resourceType), resourceID.String(), p, labelID.String())
|
|
|
|
}
|