2018-12-03 16:07:08 +00:00
|
|
|
package http
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"context"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"net/http"
|
|
|
|
"path"
|
|
|
|
|
2019-02-07 23:19:30 +00:00
|
|
|
"go.uber.org/zap"
|
|
|
|
|
2019-02-07 23:23:15 +00:00
|
|
|
platform "github.com/influxdata/influxdb"
|
2018-12-03 16:07:08 +00:00
|
|
|
"github.com/julienschmidt/httprouter"
|
|
|
|
)
|
|
|
|
|
2019-01-18 19:03:36 +00:00
|
|
|
// LabelHandler represents an HTTP API handler for labels
|
|
|
|
type LabelHandler struct {
|
|
|
|
*httprouter.Router
|
|
|
|
|
|
|
|
Logger *zap.Logger
|
|
|
|
|
|
|
|
LabelService platform.LabelService
|
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
|
|
|
labelsPath = "/api/v2/labels"
|
|
|
|
labelsIDPath = "/api/v2/labels/:id"
|
|
|
|
)
|
|
|
|
|
|
|
|
// NewLabelHandler returns a new instance of LabelHandler
|
2019-02-07 22:03:42 +00:00
|
|
|
func NewLabelHandler(s platform.LabelService) *LabelHandler {
|
2019-01-18 19:03:36 +00:00
|
|
|
h := &LabelHandler{
|
2019-02-07 22:03:42 +00:00
|
|
|
Router: NewRouter(),
|
|
|
|
Logger: zap.NewNop(),
|
|
|
|
LabelService: s,
|
2019-01-18 19:03:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
h.HandlerFunc("POST", labelsPath, h.handlePostLabel)
|
|
|
|
h.HandlerFunc("GET", labelsPath, h.handleGetLabels)
|
|
|
|
|
|
|
|
h.HandlerFunc("GET", labelsIDPath, h.handleGetLabel)
|
|
|
|
h.HandlerFunc("PATCH", labelsIDPath, h.handlePatchLabel)
|
|
|
|
h.HandlerFunc("DELETE", labelsIDPath, h.handleDeleteLabel)
|
|
|
|
|
|
|
|
return h
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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 {
|
|
|
|
EncodeError(ctx, err, w)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := h.LabelService.CreateLabel(ctx, req.Label); err != nil {
|
|
|
|
EncodeError(ctx, err, w)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := encodeResponse(ctx, w, http.StatusCreated, newLabelResponse(req.Label)); err != nil {
|
|
|
|
logEncodingError(h.Logger, r, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type postLabelRequest struct {
|
|
|
|
Label *platform.Label
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b postLabelRequest) Validate() error {
|
|
|
|
if b.Label.Name == "" {
|
|
|
|
return &platform.Error{
|
|
|
|
Code: platform.EInvalid,
|
|
|
|
Msg: "label requires a name",
|
|
|
|
}
|
|
|
|
}
|
2019-03-19 08:56:55 +00:00
|
|
|
if !b.Label.OrganizationID.Valid() {
|
|
|
|
return &platform.Error{
|
|
|
|
Code: platform.EInvalid,
|
|
|
|
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) {
|
|
|
|
l := &platform.Label{}
|
|
|
|
if err := json.NewDecoder(r.Body).Decode(l); err != nil {
|
|
|
|
return nil, &platform.Error{
|
|
|
|
Code: platform.EInvalid,
|
|
|
|
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()
|
|
|
|
|
|
|
|
labels, err := h.LabelService.FindLabels(ctx, platform.LabelFilter{})
|
|
|
|
if err != nil {
|
|
|
|
EncodeError(ctx, err, w)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
err = encodeResponse(ctx, w, http.StatusOK, newLabelsResponse(labels))
|
|
|
|
if err != nil {
|
|
|
|
EncodeError(ctx, err, w)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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 {
|
|
|
|
EncodeError(ctx, err, w)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
l, err := h.LabelService.FindLabelByID(ctx, req.LabelID)
|
|
|
|
if err != nil {
|
|
|
|
EncodeError(ctx, err, w)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := encodeResponse(ctx, w, http.StatusOK, newLabelResponse(l)); err != nil {
|
|
|
|
logEncodingError(h.Logger, r, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type getLabelRequest struct {
|
|
|
|
LabelID platform.ID
|
|
|
|
}
|
|
|
|
|
|
|
|
func decodeGetLabelRequest(ctx context.Context, r *http.Request) (*getLabelRequest, error) {
|
|
|
|
params := httprouter.ParamsFromContext(ctx)
|
|
|
|
id := params.ByName("id")
|
|
|
|
if id == "" {
|
|
|
|
return nil, &platform.Error{
|
|
|
|
Code: platform.EInvalid,
|
|
|
|
Msg: "label id is not valid",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var i platform.ID
|
|
|
|
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 {
|
|
|
|
EncodeError(ctx, err, w)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := h.LabelService.DeleteLabel(ctx, req.LabelID); err != nil {
|
|
|
|
EncodeError(ctx, err, w)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
w.WriteHeader(http.StatusNoContent)
|
|
|
|
}
|
|
|
|
|
|
|
|
type deleteLabelRequest struct {
|
|
|
|
LabelID platform.ID
|
|
|
|
}
|
|
|
|
|
|
|
|
func decodeDeleteLabelRequest(ctx context.Context, r *http.Request) (*deleteLabelRequest, error) {
|
|
|
|
params := httprouter.ParamsFromContext(ctx)
|
|
|
|
id := params.ByName("id")
|
|
|
|
if id == "" {
|
2019-01-24 00:15:42 +00:00
|
|
|
return nil, &platform.Error{
|
|
|
|
Code: platform.EInvalid,
|
|
|
|
Msg: "url missing id",
|
|
|
|
}
|
2019-01-18 19:03:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var i platform.ID
|
|
|
|
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 {
|
|
|
|
EncodeError(ctx, err, w)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
l, err := h.LabelService.UpdateLabel(ctx, req.LabelID, req.Update)
|
|
|
|
if err != nil {
|
|
|
|
EncodeError(ctx, err, w)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := encodeResponse(ctx, w, http.StatusOK, newLabelResponse(l)); err != nil {
|
|
|
|
logEncodingError(h.Logger, r, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type patchLabelRequest struct {
|
|
|
|
Update platform.LabelUpdate
|
|
|
|
LabelID platform.ID
|
|
|
|
}
|
|
|
|
|
|
|
|
func decodePatchLabelRequest(ctx context.Context, r *http.Request) (*patchLabelRequest, error) {
|
|
|
|
params := httprouter.ParamsFromContext(ctx)
|
|
|
|
id := params.ByName("id")
|
|
|
|
if id == "" {
|
2019-01-24 00:15:42 +00:00
|
|
|
return nil, &platform.Error{
|
|
|
|
Code: platform.EInvalid,
|
|
|
|
Msg: "url missing id",
|
|
|
|
}
|
2019-01-18 19:03:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var i platform.ID
|
|
|
|
if err := i.DecodeFromString(id); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
upd := &platform.LabelUpdate{}
|
|
|
|
if err := json.NewDecoder(r.Body).Decode(upd); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &patchLabelRequest{
|
|
|
|
Update: *upd,
|
|
|
|
LabelID: i,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// LabelService connects to Influx via HTTP using tokens to manage labels
|
2018-12-03 16:07:08 +00:00
|
|
|
type LabelService struct {
|
|
|
|
Addr string
|
|
|
|
Token string
|
|
|
|
InsecureSkipVerify bool
|
|
|
|
BasePath string
|
2019-01-18 19:03:36 +00:00
|
|
|
OpPrefix string
|
2018-12-03 16:07:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type labelResponse struct {
|
|
|
|
Links map[string]string `json:"links"`
|
2019-01-18 19:03:36 +00:00
|
|
|
Label platform.Label `json:"label"`
|
2018-12-03 16:07:08 +00:00
|
|
|
}
|
|
|
|
|
2019-01-18 19:03:36 +00:00
|
|
|
func newLabelResponse(l *platform.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-01-18 19:03:36 +00:00
|
|
|
Labels []*platform.Label `json:"labels"`
|
2018-12-03 16:07:08 +00:00
|
|
|
}
|
|
|
|
|
2019-01-18 19:03:36 +00:00
|
|
|
func newLabelsResponse(ls []*platform.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 {
|
|
|
|
Logger *zap.Logger
|
|
|
|
LabelService platform.LabelService
|
2019-02-07 23:23:15 +00:00
|
|
|
ResourceType platform.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-02-07 23:23:15 +00:00
|
|
|
req, err := decodeGetLabelsRequest(ctx, r, b.ResourceType)
|
2018-12-03 16:07:08 +00:00
|
|
|
if err != nil {
|
|
|
|
EncodeError(ctx, err, w)
|
|
|
|
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 {
|
|
|
|
EncodeError(ctx, err, w)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-01-18 19:03:36 +00:00
|
|
|
if err := encodeResponse(ctx, w, http.StatusOK, newLabelsResponse(labels)); err != nil {
|
2019-01-17 04:33:09 +00:00
|
|
|
logEncodingError(b.Logger, r, err)
|
2018-12-03 16:07:08 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type getLabelsRequest struct {
|
2019-01-18 19:03:36 +00:00
|
|
|
filter platform.LabelMappingFilter
|
2018-12-03 16:07:08 +00:00
|
|
|
}
|
|
|
|
|
2019-02-07 23:23:15 +00:00
|
|
|
func decodeGetLabelsRequest(ctx context.Context, r *http.Request, rt platform.ResourceType) (*getLabelsRequest, error) {
|
2018-12-03 16:07:08 +00:00
|
|
|
req := &getLabelsRequest{}
|
|
|
|
|
|
|
|
params := httprouter.ParamsFromContext(ctx)
|
|
|
|
id := params.ByName("id")
|
|
|
|
if id == "" {
|
2019-01-24 00:15:42 +00:00
|
|
|
return nil, &platform.Error{
|
|
|
|
Code: platform.EInvalid,
|
|
|
|
Msg: "url missing id",
|
|
|
|
}
|
2018-12-03 16:07:08 +00:00
|
|
|
}
|
|
|
|
|
2019-01-18 19:03:36 +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 {
|
|
|
|
EncodeError(ctx, err, w)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-01-18 19:03:36 +00:00
|
|
|
if err := req.Mapping.Validate(); err != nil {
|
2018-12-03 16:07:08 +00:00
|
|
|
EncodeError(ctx, err, w)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-01-17 04:33:09 +00:00
|
|
|
if err := b.LabelService.CreateLabelMapping(ctx, &req.Mapping); err != nil {
|
2018-12-03 16:07:08 +00:00
|
|
|
EncodeError(ctx, err, w)
|
|
|
|
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 {
|
|
|
|
EncodeError(ctx, err, w)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := encodeResponse(ctx, w, http.StatusCreated, newLabelResponse(label)); err != nil {
|
2019-01-17 04:33:09 +00:00
|
|
|
logEncodingError(b.Logger, r, err)
|
2018-12-03 16:07:08 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-18 19:03:36 +00:00
|
|
|
type postLabelMappingRequest struct {
|
|
|
|
Mapping platform.LabelMapping
|
2018-12-03 16:07:08 +00:00
|
|
|
}
|
|
|
|
|
2019-02-07 23:23:15 +00:00
|
|
|
func decodePostLabelMappingRequest(ctx context.Context, r *http.Request, rt platform.ResourceType) (*postLabelMappingRequest, error) {
|
2018-12-03 16:07:08 +00:00
|
|
|
params := httprouter.ParamsFromContext(ctx)
|
|
|
|
id := params.ByName("id")
|
|
|
|
if id == "" {
|
2019-01-24 00:15:42 +00:00
|
|
|
return nil, &platform.Error{
|
|
|
|
Code: platform.EInvalid,
|
|
|
|
Msg: "url missing id",
|
|
|
|
}
|
2018-12-03 16:07:08 +00:00
|
|
|
}
|
|
|
|
|
2019-01-18 19:03:36 +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-01-18 19:03:36 +00:00
|
|
|
mapping := &platform.LabelMapping{}
|
|
|
|
if err := json.NewDecoder(r.Body).Decode(mapping); err != nil {
|
2019-03-29 15:52:06 +00:00
|
|
|
return nil, &platform.Error{
|
|
|
|
Code: platform.EInvalid,
|
|
|
|
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 {
|
|
|
|
EncodeError(ctx, err, w)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-01-18 19:03:36 +00:00
|
|
|
mapping := &platform.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 {
|
2018-12-03 16:07:08 +00:00
|
|
|
EncodeError(ctx, err, w)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
w.WriteHeader(http.StatusNoContent)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-18 19:03:36 +00:00
|
|
|
type deleteLabelMappingRequest struct {
|
|
|
|
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 == "" {
|
2019-01-18 19:03:36 +00:00
|
|
|
return nil, &platform.Error{
|
|
|
|
Code: platform.EInvalid,
|
2018-12-18 17:14:59 +00:00
|
|
|
Msg: "url missing resource id",
|
|
|
|
}
|
2018-12-03 16:07:08 +00:00
|
|
|
}
|
|
|
|
|
2019-01-18 19:03:36 +00:00
|
|
|
var rid platform.ID
|
|
|
|
if err := rid.DecodeFromString(id); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
id = params.ByName("lid")
|
|
|
|
if id == "" {
|
|
|
|
return nil, &platform.Error{
|
|
|
|
Code: platform.EInvalid,
|
|
|
|
Msg: "label id is missing",
|
2018-12-18 17:14:59 +00:00
|
|
|
}
|
2018-12-03 16:07:08 +00:00
|
|
|
}
|
|
|
|
|
2019-01-18 19:03:36 +00:00
|
|
|
var lid platform.ID
|
|
|
|
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-01-18 19:03:36 +00:00
|
|
|
func labelIDPath(id platform.ID) string {
|
|
|
|
return path.Join(labelsPath, id.String())
|
|
|
|
}
|
|
|
|
|
|
|
|
// FindLabelByID returns a single label by ID.
|
|
|
|
func (s *LabelService) FindLabelByID(ctx context.Context, id platform.ID) (*platform.Label, error) {
|
|
|
|
u, err := newURL(s.Addr, labelIDPath(id))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
req, err := http.NewRequest("GET", u.String(), nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
SetToken(s.Token, req)
|
|
|
|
|
|
|
|
hc := newClient(u.Scheme, s.InsecureSkipVerify)
|
|
|
|
resp, err := hc.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-01-18 22:32:53 +00:00
|
|
|
defer resp.Body.Close()
|
2019-01-18 19:03:36 +00:00
|
|
|
|
2019-01-24 01:02:37 +00:00
|
|
|
if err := CheckError(resp); err != nil {
|
2019-01-18 19:03:36 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var lr labelResponse
|
|
|
|
if err := json.NewDecoder(resp.Body).Decode(&lr); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &lr.Label, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *LabelService) FindLabels(ctx context.Context, filter platform.LabelFilter, opt ...platform.FindOptions) ([]*platform.Label, error) {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// FindResourceLabels returns a list of labels, derived from a label mapping filter.
|
|
|
|
func (s *LabelService) FindResourceLabels(ctx context.Context, filter platform.LabelMappingFilter) ([]*platform.Label, error) {
|
2018-12-03 16:07:08 +00:00
|
|
|
url, err := newURL(s.Addr, resourceIDPath(s.BasePath, filter.ResourceID))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
req, err := http.NewRequest("GET", url.String(), nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
SetToken(s.Token, req)
|
|
|
|
|
|
|
|
hc := newClient(url.Scheme, s.InsecureSkipVerify)
|
|
|
|
|
|
|
|
resp, err := hc.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-01-18 22:32:53 +00:00
|
|
|
defer resp.Body.Close()
|
2018-12-03 16:07:08 +00:00
|
|
|
|
|
|
|
if err := CheckError(resp); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var r labelsResponse
|
|
|
|
if err := json.NewDecoder(resp.Body).Decode(&r); err != nil {
|
|
|
|
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.
|
|
|
|
func (s *LabelService) CreateLabel(ctx context.Context, l *platform.Label) error {
|
|
|
|
u, err := newURL(s.Addr, labelsPath)
|
|
|
|
if err != nil {
|
2018-12-03 16:07:08 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-01-18 19:03:36 +00:00
|
|
|
octets, err := json.Marshal(l)
|
2018-12-03 16:07:08 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-01-18 19:03:36 +00:00
|
|
|
req, err := http.NewRequest("POST", u.String(), bytes.NewReader(octets))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
SetToken(s.Token, req)
|
|
|
|
|
|
|
|
hc := newClient(u.Scheme, s.InsecureSkipVerify)
|
|
|
|
|
|
|
|
resp, err := hc.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-01-18 22:32:53 +00:00
|
|
|
defer resp.Body.Close()
|
2019-01-18 19:03:36 +00:00
|
|
|
|
|
|
|
// TODO(jsternberg): Should this check for a 201 explicitly?
|
2019-01-24 01:02:37 +00:00
|
|
|
if err := CheckError(resp); err != nil {
|
2019-01-18 19:03:36 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
var lr labelResponse
|
|
|
|
if err := json.NewDecoder(resp.Body).Decode(&lr); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *LabelService) CreateLabelMapping(ctx context.Context, m *platform.LabelMapping) error {
|
|
|
|
if err := m.Validate(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-01-22 17:55:04 +00:00
|
|
|
url, err := newURL(s.Addr, resourceIDPath(s.BasePath, m.ResourceID))
|
2019-01-18 19:03:36 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
octets, err := json.Marshal(m)
|
2018-12-03 16:07:08 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
req, err := http.NewRequest("POST", url.String(), bytes.NewReader(octets))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
SetToken(s.Token, req)
|
|
|
|
|
|
|
|
hc := newClient(url.Scheme, s.InsecureSkipVerify)
|
|
|
|
|
|
|
|
resp, err := hc.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-01-18 22:32:53 +00:00
|
|
|
defer resp.Body.Close()
|
2018-12-03 16:07:08 +00:00
|
|
|
|
|
|
|
if err := CheckError(resp); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-01-18 19:03:36 +00:00
|
|
|
if err := json.NewDecoder(resp.Body).Decode(m); err != nil {
|
2018-12-03 16:07:08 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-01-18 19:03:36 +00:00
|
|
|
// UpdateLabel updates a label and returns the updated label.
|
|
|
|
func (s *LabelService) UpdateLabel(ctx context.Context, id platform.ID, upd platform.LabelUpdate) (*platform.Label, error) {
|
|
|
|
u, err := newURL(s.Addr, labelIDPath(id))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
octets, err := json.Marshal(upd)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
req, err := http.NewRequest("PATCH", u.String(), bytes.NewReader(octets))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
SetToken(s.Token, req)
|
|
|
|
|
|
|
|
hc := newClient(u.Scheme, s.InsecureSkipVerify)
|
|
|
|
|
|
|
|
resp, err := hc.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-01-18 22:32:53 +00:00
|
|
|
defer resp.Body.Close()
|
2019-01-18 19:03:36 +00:00
|
|
|
|
2019-01-24 01:02:37 +00:00
|
|
|
if err := CheckError(resp); err != nil {
|
2019-01-18 19:03:36 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var lr labelResponse
|
|
|
|
if err := json.NewDecoder(resp.Body).Decode(&lr); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &lr.Label, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// DeleteLabel removes a label by ID.
|
|
|
|
func (s *LabelService) DeleteLabel(ctx context.Context, id platform.ID) error {
|
|
|
|
u, err := newURL(s.Addr, labelIDPath(id))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
req, err := http.NewRequest("DELETE", u.String(), nil)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
SetToken(s.Token, req)
|
|
|
|
|
|
|
|
hc := newClient(u.Scheme, s.InsecureSkipVerify)
|
|
|
|
resp, err := hc.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-01-18 22:32:53 +00:00
|
|
|
defer resp.Body.Close()
|
|
|
|
|
2019-01-24 01:02:37 +00:00
|
|
|
return CheckError(resp)
|
2019-01-18 19:03:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *LabelService) DeleteLabelMapping(ctx context.Context, m *platform.LabelMapping) error {
|
2019-01-22 17:55:04 +00:00
|
|
|
url, err := newURL(s.Addr, labelNamePath(s.BasePath, m.ResourceID, m.LabelID))
|
2018-12-03 16:07:08 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
req, err := http.NewRequest("DELETE", url.String(), nil)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
SetToken(s.Token, req)
|
|
|
|
|
|
|
|
hc := newClient(url.Scheme, s.InsecureSkipVerify)
|
|
|
|
resp, err := hc.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-01-18 22:32:53 +00:00
|
|
|
defer resp.Body.Close()
|
|
|
|
|
2018-12-03 16:07:08 +00:00
|
|
|
return CheckError(resp)
|
|
|
|
}
|
|
|
|
|
2019-01-18 19:03:36 +00:00
|
|
|
func labelNamePath(basePath string, resourceID platform.ID, labelID platform.ID) string {
|
|
|
|
return path.Join(basePath, resourceID.String(), "labels", labelID.String())
|
2018-12-03 16:07:08 +00:00
|
|
|
}
|