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"
|
|
|
|
"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
|
2019-06-27 01:33:20 +00:00
|
|
|
influxdb.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
|
2019-12-04 23:10:23 +00:00
|
|
|
func NewLabelHandler(log *zap.Logger, s influxdb.LabelService, he influxdb.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 == "" {
|
2019-04-11 05:05:17 +00:00
|
|
|
return &influxdb.Error{
|
|
|
|
Code: influxdb.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() {
|
2019-04-11 05:05:17 +00:00
|
|
|
return &influxdb.Error{
|
|
|
|
Code: influxdb.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 {
|
2019-04-11 05:05:17 +00:00
|
|
|
return nil, &influxdb.Error{
|
|
|
|
Code: influxdb.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
|
|
|
|
}
|
2019-12-04 23:10:23 +00:00
|
|
|
h.log.Debug("Labels retrived", 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 != "" {
|
|
|
|
id, err := influxdb.IDFromString(orgID)
|
|
|
|
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 {
|
2019-04-11 05:05:17 +00:00
|
|
|
LabelID influxdb.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 == "" {
|
2019-04-11 05:05:17 +00:00
|
|
|
return nil, &influxdb.Error{
|
|
|
|
Code: influxdb.EInvalid,
|
2019-01-18 19:03:36 +00:00
|
|
|
Msg: "label id is not valid",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-11 05:05:17 +00:00
|
|
|
var i influxdb.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 {
|
2019-04-11 05:05:17 +00:00
|
|
|
LabelID influxdb.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 == "" {
|
2019-04-11 05:05:17 +00:00
|
|
|
return nil, &influxdb.Error{
|
|
|
|
Code: influxdb.EInvalid,
|
2019-01-24 00:15:42 +00:00
|
|
|
Msg: "url missing id",
|
|
|
|
}
|
2019-01-18 19:03:36 +00:00
|
|
|
}
|
|
|
|
|
2019-04-11 05:05:17 +00:00
|
|
|
var i influxdb.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
|
|
|
|
LabelID influxdb.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 == "" {
|
2019-04-11 05:05:17 +00:00
|
|
|
return nil, &influxdb.Error{
|
|
|
|
Code: influxdb.EInvalid,
|
2019-01-24 00:15:42 +00:00
|
|
|
Msg: "url missing id",
|
|
|
|
}
|
2019-01-18 19:03:36 +00:00
|
|
|
}
|
|
|
|
|
2019-04-11 05:05:17 +00:00
|
|
|
var i influxdb.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{
|
2019-01-18 19:03:36 +00:00
|
|
|
"self": fmt.Sprintf("/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
|
2019-06-27 01:33:20 +00:00
|
|
|
influxdb.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 == "" {
|
2019-04-11 05:05:17 +00:00
|
|
|
return nil, &influxdb.Error{
|
|
|
|
Code: influxdb.EInvalid,
|
2019-01-24 00:15:42 +00:00
|
|
|
Msg: "url missing id",
|
|
|
|
}
|
2018-12-03 16:07:08 +00:00
|
|
|
}
|
|
|
|
|
2019-04-11 05:05:17 +00:00
|
|
|
var i influxdb.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 == "" {
|
2019-04-11 05:05:17 +00:00
|
|
|
return nil, &influxdb.Error{
|
|
|
|
Code: influxdb.EInvalid,
|
2019-01-24 00:15:42 +00:00
|
|
|
Msg: "url missing id",
|
|
|
|
}
|
2018-12-03 16:07:08 +00:00
|
|
|
}
|
|
|
|
|
2019-04-11 05:05:17 +00:00
|
|
|
var rid influxdb.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 {
|
2019-04-11 05:05:17 +00:00
|
|
|
return nil, &influxdb.Error{
|
|
|
|
Code: influxdb.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 {
|
2019-04-11 05:05:17 +00:00
|
|
|
ResourceID influxdb.ID
|
|
|
|
LabelID influxdb.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 == "" {
|
2019-04-11 05:05:17 +00:00
|
|
|
return nil, &influxdb.Error{
|
|
|
|
Code: influxdb.EInvalid,
|
2018-12-18 17:14:59 +00:00
|
|
|
Msg: "url missing resource id",
|
|
|
|
}
|
2018-12-03 16:07:08 +00:00
|
|
|
}
|
|
|
|
|
2019-04-11 05:05:17 +00:00
|
|
|
var rid influxdb.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 == "" {
|
2019-04-11 05:05:17 +00:00
|
|
|
return nil, &influxdb.Error{
|
|
|
|
Code: influxdb.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
|
|
|
}
|
|
|
|
|
2019-04-11 05:05:17 +00:00
|
|
|
var lid influxdb.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
|
|
|
}
|
|
|
|
|
2019-04-11 05:05:17 +00:00
|
|
|
func labelIDPath(id influxdb.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.
|
2019-04-11 05:05:17 +00:00
|
|
|
func (s *LabelService) FindLabelByID(ctx context.Context, id influxdb.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.
|
2019-04-11 05:05:17 +00:00
|
|
|
func (s *LabelService) UpdateLabel(ctx context.Context, id influxdb.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.
|
2019-04-11 05:05:17 +00:00
|
|
|
func (s *LabelService) DeleteLabel(ctx context.Context, id influxdb.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.
|
|
|
|
Delete(resourceIDPath(m.ResourceType, m.ResourceID, "labels")).
|
|
|
|
Do(ctx)
|
2018-12-03 16:07:08 +00:00
|
|
|
}
|