Merge pull request #18096 from influxdata/http-check-client-disconnect

feat(http): Client disconnections should return a HTTP 499 error code.
pull/18114/head
Ben Johnson 2020-05-15 08:04:52 -06:00 committed by GitHub
commit 2ea1eb9491
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 222 additions and 212 deletions

View File

@ -75,13 +75,13 @@ func (h *AuthHandler) handlePostAuthorization(w http.ResponseWriter, r *http.Req
ctx := r.Context()
a, err := decodePostAuthorizationRequest(ctx, r)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
user, err := getAuthorizedUser(r, h.tenantService)
if err != nil {
h.api.Err(w, influxdb.ErrUnableToCreateToken)
h.api.Err(w, r, influxdb.ErrUnableToCreateToken)
return
}
@ -93,13 +93,13 @@ func (h *AuthHandler) handlePostAuthorization(w http.ResponseWriter, r *http.Req
auth := a.toInfluxdb(userID)
if err := h.authSvc.CreateAuthorization(ctx, auth); err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
perms, err := newPermissionsResponse(ctx, auth.Permissions, h.lookupService)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
@ -107,11 +107,11 @@ func (h *AuthHandler) handlePostAuthorization(w http.ResponseWriter, r *http.Req
resp, err := h.newAuthResponse(ctx, auth, perms)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
h.api.Respond(w, http.StatusCreated, resp)
h.api.Respond(w, r, http.StatusCreated, resp)
}
func getAuthorizedUser(r *http.Request, ts TenantService) (*influxdb.User, error) {
@ -352,7 +352,7 @@ func (h *AuthHandler) handleGetAuthorizations(w http.ResponseWriter, r *http.Req
req, err := decodeGetAuthorizationsRequest(ctx, r)
if err != nil {
h.log.Info("Failed to decode request", zap.String("handler", "getAuthorizations"), zap.Error(err))
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
@ -360,7 +360,7 @@ func (h *AuthHandler) handleGetAuthorizations(w http.ResponseWriter, r *http.Req
as, _, err := h.authSvc.FindAuthorizations(ctx, req.filter, opts)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
@ -369,7 +369,7 @@ func (h *AuthHandler) handleGetAuthorizations(w http.ResponseWriter, r *http.Req
if f.User != nil {
u, err := h.tenantService.FindUser(ctx, influxdb.UserFilter{Name: f.User})
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
f.UserID = &u.ID
@ -378,7 +378,7 @@ func (h *AuthHandler) handleGetAuthorizations(w http.ResponseWriter, r *http.Req
if f.Org != nil {
o, err := h.tenantService.FindOrganization(ctx, influxdb.OrganizationFilter{Name: f.Org})
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
f.OrgID = &o.ID
@ -388,7 +388,7 @@ func (h *AuthHandler) handleGetAuthorizations(w http.ResponseWriter, r *http.Req
for _, a := range as {
ps, err := newPermissionsResponse(ctx, a.Permissions, h.lookupService)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
@ -402,7 +402,7 @@ func (h *AuthHandler) handleGetAuthorizations(w http.ResponseWriter, r *http.Req
h.log.Debug("Auths retrieved ", zap.String("auths", fmt.Sprint(auths)))
h.api.Respond(w, http.StatusOK, newAuthsResponse(auths))
h.api.Respond(w, r, http.StatusOK, newAuthsResponse(auths))
}
type getAuthorizationsRequest struct {
@ -460,20 +460,20 @@ func (h *AuthHandler) handleGetAuthorization(w http.ResponseWriter, r *http.Requ
id, err := influxdb.IDFromString(chi.URLParam(r, "id"))
if err != nil {
h.log.Info("Failed to decode request", zap.String("handler", "getAuthorization"), zap.Error(err))
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
a, err := h.authSvc.FindAuthorizationByID(ctx, *id)
if err != nil {
// Don't log here, it should already be handled by the service
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
ps, err := newPermissionsResponse(ctx, a.Permissions, h.lookupService)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
@ -481,11 +481,11 @@ func (h *AuthHandler) handleGetAuthorization(w http.ResponseWriter, r *http.Requ
resp, err := h.newAuthResponse(ctx, a, ps)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
h.api.Respond(w, http.StatusOK, resp)
h.api.Respond(w, r, http.StatusOK, resp)
}
// handleUpdateAuthorization is the HTTP handler for the PATCH /api/v2/authorizations/:id route that updates the authorization's status and desc.
@ -494,36 +494,36 @@ func (h *AuthHandler) handleUpdateAuthorization(w http.ResponseWriter, r *http.R
req, err := decodeUpdateAuthorizationRequest(ctx, r)
if err != nil {
h.log.Info("Failed to decode request", zap.String("handler", "updateAuthorization"), zap.Error(err))
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
a, err := h.authSvc.FindAuthorizationByID(ctx, req.ID)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
a, err = h.authSvc.UpdateAuthorization(ctx, a.ID, req.AuthorizationUpdate)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
ps, err := newPermissionsResponse(ctx, a.Permissions, h.lookupService)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
h.log.Debug("Auth updated", zap.String("auth", fmt.Sprint(a)))
resp, err := h.newAuthResponse(ctx, a, ps)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
h.api.Respond(w, http.StatusOK, resp)
h.api.Respond(w, r, http.StatusOK, resp)
}
type updateAuthorizationRequest struct {
@ -553,13 +553,13 @@ func (h *AuthHandler) handleDeleteAuthorization(w http.ResponseWriter, r *http.R
id, err := influxdb.IDFromString(chi.URLParam(r, "id"))
if err != nil {
h.log.Info("Failed to decode request", zap.String("handler", "deleteAuthorization"), zap.Error(err))
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
if err := h.authSvc.DeleteAuthorization(r.Context(), *id); err != nil {
// Don't log here, it should already be handled by the service
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}

View File

@ -321,18 +321,18 @@ func newBucketsResponse(ctx context.Context, opts influxdb.FindOptions, f influx
func (h *BucketHandler) handlePostBucket(w http.ResponseWriter, r *http.Request) {
var b postBucketRequest
if err := h.api.DecodeJSON(r.Body, &b); err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
bucket := b.toInfluxDB()
if err := h.BucketService.CreateBucket(r.Context(), bucket); err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
h.log.Debug("Bucket created", zap.String("bucket", fmt.Sprint(bucket)))
h.api.Respond(w, http.StatusCreated, NewBucketResponse(bucket, []*influxdb.Label{}))
h.api.Respond(w, r, http.StatusCreated, NewBucketResponse(bucket, []*influxdb.Label{}))
}
type postBucketRequest struct {
@ -395,25 +395,25 @@ func (h *BucketHandler) handleGetBucket(w http.ResponseWriter, r *http.Request)
id, err := decodeIDFromCtx(r.Context(), "id")
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
b, err := h.BucketService.FindBucketByID(ctx, id)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
labels, err := h.LabelService.FindResourceLabels(ctx, influxdb.LabelMappingFilter{ResourceID: b.ID, ResourceType: influxdb.BucketsResourceType})
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
h.log.Debug("Bucket retrieved", zap.String("bucket", fmt.Sprint(b)))
h.api.Respond(w, http.StatusOK, NewBucketResponse(b, labels))
h.api.Respond(w, r, http.StatusOK, NewBucketResponse(b, labels))
}
func bucketIDPath(id influxdb.ID) string {
@ -424,25 +424,25 @@ func bucketIDPath(id influxdb.ID) string {
func (h *BucketHandler) handleGetBucketLog(w http.ResponseWriter, r *http.Request) {
id, err := decodeIDFromCtx(r.Context(), "id")
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
opts, err := influxdb.DecodeFindOptions(r)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
log, _, err := h.BucketOperationLogService.GetBucketOperationLog(r.Context(), id, *opts)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
h.log.Debug("Bucket log retrived", zap.String("bucket", fmt.Sprint(log)))
h.api.Respond(w, http.StatusOK, newBucketLogResponse(id, log))
h.api.Respond(w, r, http.StatusOK, newBucketLogResponse(id, log))
}
func newBucketLogResponse(id influxdb.ID, es []*influxdb.OperationLogEntry) *operationLogResponse {
@ -462,18 +462,18 @@ func newBucketLogResponse(id influxdb.ID, es []*influxdb.OperationLogEntry) *ope
func (h *BucketHandler) handleDeleteBucket(w http.ResponseWriter, r *http.Request) {
id, err := decodeIDFromCtx(r.Context(), "id")
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
if err := h.BucketService.DeleteBucket(r.Context(), id); err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
h.log.Debug("Bucket deleted", zap.String("bucketID", id.String()))
h.api.Respond(w, http.StatusNoContent, nil)
h.api.Respond(w, r, http.StatusNoContent, nil)
}
// handleGetBuckets is the HTTP handler for the GET /api/v2/buckets route.
@ -489,7 +489,7 @@ func (h *BucketHandler) handleGetBuckets(w http.ResponseWriter, r *http.Request)
bucketID, err := decodeIDFromQuery(q, "id")
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
if bucketID > 0 {
@ -498,7 +498,7 @@ func (h *BucketHandler) handleGetBuckets(w http.ResponseWriter, r *http.Request)
orgID, err := decodeIDFromQuery(q, "orgID")
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
if orgID > 0 {
@ -507,18 +507,18 @@ func (h *BucketHandler) handleGetBuckets(w http.ResponseWriter, r *http.Request)
opts, err := influxdb.DecodeFindOptions(r)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
bs, _, err := h.BucketService.FindBuckets(r.Context(), filter, *opts)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
h.log.Debug("Buckets retrieved", zap.String("buckets", fmt.Sprint(bs)))
h.api.Respond(w, http.StatusOK, newBucketsResponse(r.Context(), *opts, filter, bs, h.LabelService))
h.api.Respond(w, r, http.StatusOK, newBucketsResponse(r.Context(), *opts, filter, bs, h.LabelService))
}
type getBucketsRequest struct {
@ -568,32 +568,32 @@ func decodeGetBucketsRequest(r *http.Request) (*getBucketsRequest, error) {
func (h *BucketHandler) handlePatchBucket(w http.ResponseWriter, r *http.Request) {
id, err := decodeIDFromCtx(r.Context(), "id")
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
var reqBody bucketUpdate
if err := h.api.DecodeJSON(r.Body, &reqBody); err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
if reqBody.Name != nil {
b, err := h.BucketService.FindBucketByID(r.Context(), id)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
b.Name = *reqBody.Name
if err := validBucketName(b); err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
}
b, err := h.BucketService.UpdateBucket(r.Context(), id, *reqBody.toInfluxDB())
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
@ -604,12 +604,12 @@ func (h *BucketHandler) handlePatchBucket(w http.ResponseWriter, r *http.Request
ResourceType: influxdb.BucketsResourceType,
})
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
h.log.Debug("Bucket updated", zap.String("bucket", fmt.Sprint(b)))
h.api.Respond(w, http.StatusOK, NewBucketResponse(b, labels))
h.api.Respond(w, r, http.StatusOK, NewBucketResponse(b, labels))
}
// BucketService connects to Influx via HTTP using tokens to manage buckets

View File

@ -79,12 +79,12 @@ func checkOrganizationExists(orgHandler *OrgHandler) kithttp.Middleware {
ctx := r.Context()
orgID, err := decodeIDFromCtx(ctx, "id")
if err != nil {
orgHandler.API.Err(w, err)
orgHandler.API.Err(w, r, err)
return
}
if _, err := orgHandler.OrgSVC.FindOrganizationByID(ctx, orgID); err != nil {
orgHandler.API.Err(w, err)
orgHandler.API.Err(w, r, err)
return
}
next.ServeHTTP(w, r)
@ -210,35 +210,35 @@ func newOrgResponse(o influxdb.Organization) orgResponse {
func (h *OrgHandler) handlePostOrg(w http.ResponseWriter, r *http.Request) {
var org influxdb.Organization
if err := h.API.DecodeJSON(r.Body, &org); err != nil {
h.API.Err(w, err)
h.API.Err(w, r, err)
return
}
if err := h.OrgSVC.CreateOrganization(r.Context(), &org); err != nil {
h.API.Err(w, err)
h.API.Err(w, r, err)
return
}
h.log.Debug("Org created", zap.String("org", fmt.Sprint(org)))
h.API.Respond(w, http.StatusCreated, newOrgResponse(org))
h.API.Respond(w, r, http.StatusCreated, newOrgResponse(org))
}
// handleGetOrg is the HTTP handler for the GET /api/v2/orgs/:id route.
func (h *OrgHandler) handleGetOrg(w http.ResponseWriter, r *http.Request) {
id, err := decodeIDFromCtx(r.Context(), "id")
if err != nil {
h.API.Err(w, err)
h.API.Err(w, r, err)
return
}
org, err := h.OrgSVC.FindOrganizationByID(r.Context(), id)
if err != nil {
h.API.Err(w, err)
h.API.Err(w, r, err)
return
}
h.log.Debug("Org retrieved", zap.String("org", fmt.Sprint(org)))
h.API.Respond(w, http.StatusOK, newOrgResponse(*org))
h.API.Respond(w, r, http.StatusOK, newOrgResponse(*org))
}
// handleGetOrgs is the HTTP handler for the GET /api/v2/orgs route.
@ -251,7 +251,7 @@ func (h *OrgHandler) handleGetOrgs(w http.ResponseWriter, r *http.Request) {
if orgID := qp.Get("orgID"); orgID != "" {
id, err := influxdb.IDFromString(orgID)
if err != nil {
h.API.Err(w, err)
h.API.Err(w, r, err)
return
}
filter.ID = id
@ -260,7 +260,7 @@ func (h *OrgHandler) handleGetOrgs(w http.ResponseWriter, r *http.Request) {
if userID := qp.Get("userID"); userID != "" {
id, err := influxdb.IDFromString(userID)
if err != nil {
h.API.Err(w, err)
h.API.Err(w, r, err)
return
}
filter.UserID = id
@ -268,54 +268,54 @@ func (h *OrgHandler) handleGetOrgs(w http.ResponseWriter, r *http.Request) {
orgs, _, err := h.OrgSVC.FindOrganizations(r.Context(), filter)
if err != nil {
h.API.Err(w, err)
h.API.Err(w, r, err)
return
}
h.log.Debug("Orgs retrieved", zap.String("org", fmt.Sprint(orgs)))
h.API.Respond(w, http.StatusOK, newOrgsResponse(orgs))
h.API.Respond(w, r, http.StatusOK, newOrgsResponse(orgs))
}
// handleDeleteOrganization is the HTTP handler for the DELETE /api/v2/orgs/:id route.
func (h *OrgHandler) handleDeleteOrg(w http.ResponseWriter, r *http.Request) {
id, err := decodeIDFromCtx(r.Context(), "id")
if err != nil {
h.API.Err(w, err)
h.API.Err(w, r, err)
return
}
ctx := r.Context()
if err := h.OrgSVC.DeleteOrganization(ctx, id); err != nil {
h.API.Err(w, err)
h.API.Err(w, r, err)
return
}
h.log.Debug("Org deleted", zap.String("orgID", fmt.Sprint(id)))
h.API.Respond(w, http.StatusNoContent, nil)
h.API.Respond(w, r, http.StatusNoContent, nil)
}
// handlePatchOrg is the HTTP handler for the PATH /api/v2/orgs route.
func (h *OrgHandler) handlePatchOrg(w http.ResponseWriter, r *http.Request) {
id, err := decodeIDFromCtx(r.Context(), "id")
if err != nil {
h.API.Err(w, err)
h.API.Err(w, r, err)
return
}
var upd influxdb.OrganizationUpdate
if err := h.API.DecodeJSON(r.Body, &upd); err != nil {
h.API.Err(w, err)
h.API.Err(w, r, err)
return
}
org, err := h.OrgSVC.UpdateOrganization(r.Context(), id, upd)
if err != nil {
h.API.Err(w, err)
h.API.Err(w, r, err)
return
}
h.log.Debug("Org updated", zap.String("org", fmt.Sprint(org)))
h.API.Respond(w, http.StatusOK, newOrgResponse(*org))
h.API.Respond(w, r, http.StatusOK, newOrgResponse(*org))
}
type secretsResponse struct {
@ -340,39 +340,39 @@ func newSecretsResponse(orgID influxdb.ID, ks []string) *secretsResponse {
func (h *OrgHandler) handleGetSecrets(w http.ResponseWriter, r *http.Request) {
orgID, err := decodeIDFromCtx(r.Context(), "id")
if err != nil {
h.API.Err(w, err)
h.API.Err(w, r, err)
return
}
ks, err := h.SecretService.GetSecretKeys(r.Context(), orgID)
if err != nil && influxdb.ErrorCode(err) != influxdb.ENotFound {
h.API.Err(w, err)
h.API.Err(w, r, err)
return
}
h.API.Respond(w, http.StatusOK, newSecretsResponse(orgID, ks))
h.API.Respond(w, r, http.StatusOK, newSecretsResponse(orgID, ks))
}
// handleGetPatchSecrets is the HTTP handler for the PATCH /api/v2/orgs/:id/secrets route.
func (h *OrgHandler) handlePatchSecrets(w http.ResponseWriter, r *http.Request) {
orgID, err := decodeIDFromCtx(r.Context(), "id")
if err != nil {
h.API.Err(w, err)
h.API.Err(w, r, err)
return
}
var secrets map[string]string
if err := h.API.DecodeJSON(r.Body, &secrets); err != nil {
h.API.Err(w, err)
h.API.Err(w, r, err)
return
}
if err := h.SecretService.PatchSecrets(r.Context(), orgID, secrets); err != nil {
h.API.Err(w, err)
h.API.Err(w, r, err)
return
}
h.API.Respond(w, http.StatusNoContent, nil)
h.API.Respond(w, r, http.StatusNoContent, nil)
}
type secretsDeleteBody struct {
@ -383,47 +383,47 @@ type secretsDeleteBody struct {
func (h *OrgHandler) handleDeleteSecrets(w http.ResponseWriter, r *http.Request) {
orgID, err := decodeIDFromCtx(r.Context(), "id")
if err != nil {
h.API.Err(w, err)
h.API.Err(w, r, err)
return
}
var reqBody secretsDeleteBody
if err := h.API.DecodeJSON(r.Body, &reqBody); err != nil {
h.API.Err(w, err)
h.API.Err(w, r, err)
return
}
if err := h.SecretService.DeleteSecret(r.Context(), orgID, reqBody.Secrets...); err != nil {
h.API.Err(w, err)
h.API.Err(w, r, err)
return
}
h.API.Respond(w, http.StatusNoContent, nil)
h.API.Respond(w, r, http.StatusNoContent, nil)
}
// hanldeGetOrganizationLog retrieves a organization log by the organizations ID.
func (h *OrgHandler) handleGetOrgLog(w http.ResponseWriter, r *http.Request) {
orgID, err := decodeIDFromCtx(r.Context(), "id")
if err != nil {
h.API.Err(w, err)
h.API.Err(w, r, err)
return
}
opts, err := influxdb.DecodeFindOptions(r)
if err != nil {
h.API.Err(w, err)
h.API.Err(w, r, err)
return
}
log, _, err := h.OrganizationOperationLogService.GetOrganizationOperationLog(r.Context(), orgID, *opts)
if err != nil {
h.API.Err(w, err)
h.API.Err(w, r, err)
return
}
h.log.Debug("Org logs retrieved", zap.String("log", fmt.Sprint(log)))
h.API.Respond(w, http.StatusOK, newOrganizationLogResponse(orgID, log))
h.API.Respond(w, r, http.StatusOK, newOrganizationLogResponse(orgID, log))
}
func newOrganizationLogResponse(id influxdb.ID, es []*influxdb.OperationLogEntry) *operationLogResponse {

View File

@ -2,6 +2,7 @@ package http
import (
"compress/gzip"
"context"
"encoding/gob"
"encoding/json"
"fmt"
@ -26,7 +27,7 @@ type API struct {
unmarshalErrFn func(encoding string, err error) error
okErrFn func(err error) error
errFn func(err error) (interface{}, int, error)
errFn func(ctx context.Context, err error) (interface{}, int, error)
}
// APIOptFn is a functional option for setting fields on the API type.
@ -40,7 +41,7 @@ func WithLog(logger *zap.Logger) APIOptFn {
}
// WithErrFn sets the err handling func for issues when writing to the response body.
func WithErrFn(fn func(err error) (interface{}, int, error)) APIOptFn {
func WithErrFn(fn func(ctx context.Context, err error) (interface{}, int, error)) APIOptFn {
return func(api *API) {
api.errFn = fn
}
@ -86,7 +87,7 @@ func NewAPI(opts ...APIOptFn) *API {
Msg: fmt.Sprintf("failed to unmarshal %s: %s", encoding, err),
}
},
errFn: func(err error) (interface{}, int, error) {
errFn: func(ctx context.Context, err error) (interface{}, int, error) {
msg := err.Error()
if msg == "" {
msg = "an internal error has occurred"
@ -95,7 +96,7 @@ func NewAPI(opts ...APIOptFn) *API {
return ErrBody{
Code: code,
Msg: msg,
}, ErrorCodeToStatusCode(code), nil
}, ErrorCodeToStatusCode(ctx, code), nil
},
}
for _, o := range opts {
@ -144,7 +145,7 @@ func (a *API) decode(encoding string, dec decoder, v interface{}) error {
}
// Respond writes to the response writer, handling all errors in writing.
func (a *API) Respond(w http.ResponseWriter, status int, v interface{}) {
func (a *API) Respond(w http.ResponseWriter, r *http.Request, status int, v interface{}) {
if status == http.StatusNoContent {
w.WriteHeader(status)
return
@ -179,7 +180,7 @@ func (a *API) Respond(w http.ResponseWriter, status int, v interface{}) {
b, err = json.Marshal(v)
}
if err != nil {
a.Err(w, err)
a.Err(w, r, err)
return
}
@ -194,17 +195,17 @@ func (a *API) Respond(w http.ResponseWriter, status int, v interface{}) {
}
// Err is used for writing an error to the response.
func (a *API) Err(w http.ResponseWriter, err error) {
func (a *API) Err(w http.ResponseWriter, r *http.Request, err error) {
if err == nil {
return
}
a.logErr("api error encountered", zap.Error(err))
v, status, err := a.errFn(err)
v, status, err := a.errFn(r.Context(), err)
if err != nil {
a.logErr("failed to write err to response writer", zap.Error(err))
a.Respond(w, http.StatusInternalServerError, ErrBody{
a.Respond(w, r, http.StatusInternalServerError, ErrBody{
Code: "internal error",
Msg: "an unexpected error occured",
})
@ -215,7 +216,7 @@ func (a *API) Err(w http.ResponseWriter, err error) {
w.Header().Set(PlatformErrorCodeHeader, eb.Code)
}
a.Respond(w, status, v)
a.Respond(w, r, status, v)
}
func (a *API) logErr(msg string, fields ...zap.Field) {

View File

@ -142,7 +142,7 @@ func Test_API(t *testing.T) {
responder := kithttp.NewAPI()
svr := func(w http.ResponseWriter, r *http.Request) {
responder.Respond(w, statusCode, map[string]string{
responder.Respond(w, r, statusCode, map[string]string{
"foo": "bar",
})
}
@ -208,7 +208,7 @@ func Test_API(t *testing.T) {
responder := kithttp.NewAPI()
svr := func(w http.ResponseWriter, r *http.Request) {
responder.Err(w, tt.expectedErr)
responder.Err(w, r, tt.expectedErr)
}
testttp.

View File

@ -23,7 +23,7 @@ func (h ErrorHandler) HandleHTTPError(ctx context.Context, err error, w http.Res
code := influxdb.ErrorCode(err)
w.Header().Set(PlatformErrorCodeHeader, code)
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(ErrorCodeToStatusCode(code))
w.WriteHeader(ErrorCodeToStatusCode(ctx, code))
var e struct {
Code string `json:"code"`
Message string `json:"message"`
@ -51,12 +51,21 @@ func StatusCodeToErrorCode(statusCode int) string {
// ErrorCodeToStatusCode maps an influxdb error code string to a
// http status code integer.
func ErrorCodeToStatusCode(code string) int {
func ErrorCodeToStatusCode(ctx context.Context, code string) int {
// If the client disconnects early or times out then return a different
// error than the passed in error code. Client timeouts return a 408
// while disconnections return a non-standard Nginx HTTP 499 code.
if err := ctx.Err(); err == context.DeadlineExceeded {
return http.StatusRequestTimeout
} else if err == context.Canceled {
return 499 // https://httpstatuses.com/499
}
// Otherwise map internal error codes to HTTP status codes.
statusCode, ok := influxDBErrorToStatusCode[code]
if ok {
return statusCode
}
return http.StatusInternalServerError
}

View File

@ -79,7 +79,7 @@ func (s *HTTPServer) listStacks(w http.ResponseWriter, r *http.Request) {
rawOrgID := q.Get("orgID")
orgID, err := influxdb.IDFromString(rawOrgID)
if err != nil {
s.api.Err(w, &influxdb.Error{
s.api.Err(w, r, &influxdb.Error{
Code: influxdb.EInvalid,
Msg: fmt.Sprintf("organization id[%q] is invalid", rawOrgID),
Err: err,
@ -88,7 +88,7 @@ func (s *HTTPServer) listStacks(w http.ResponseWriter, r *http.Request) {
}
if err := r.ParseForm(); err != nil {
s.api.Err(w, &influxdb.Error{
s.api.Err(w, r, &influxdb.Error{
Code: influxdb.EInvalid,
Msg: "failed to parse form from encoded url",
Err: err,
@ -103,7 +103,7 @@ func (s *HTTPServer) listStacks(w http.ResponseWriter, r *http.Request) {
for _, idRaw := range r.Form["stackID"] {
id, err := influxdb.IDFromString(idRaw)
if err != nil {
s.api.Err(w, &influxdb.Error{
s.api.Err(w, r, &influxdb.Error{
Code: influxdb.EInvalid,
Msg: fmt.Sprintf("stack ID[%q] provided is invalid", idRaw),
Err: err,
@ -115,14 +115,14 @@ func (s *HTTPServer) listStacks(w http.ResponseWriter, r *http.Request) {
stacks, err := s.svc.ListStacks(r.Context(), *orgID, filter)
if err != nil {
s.api.Err(w, err)
s.api.Err(w, r, err)
return
}
if stacks == nil {
stacks = []Stack{}
}
s.api.Respond(w, http.StatusOK, RespListStacks{
s.api.Respond(w, r, http.StatusOK, RespListStacks{
Stacks: stacks,
})
}
@ -174,14 +174,14 @@ type RespCreateStack struct {
func (s *HTTPServer) createStack(w http.ResponseWriter, r *http.Request) {
var reqBody ReqCreateStack
if err := s.api.DecodeJSON(r.Body, &reqBody); err != nil {
s.api.Err(w, err)
s.api.Err(w, r, err)
return
}
defer r.Body.Close()
auth, err := pctx.GetAuthorizer(r.Context())
if err != nil {
s.api.Err(w, err)
s.api.Err(w, r, err)
return
}
@ -192,11 +192,11 @@ func (s *HTTPServer) createStack(w http.ResponseWriter, r *http.Request) {
URLs: reqBody.URLs,
})
if err != nil {
s.api.Err(w, err)
s.api.Err(w, r, err)
return
}
s.api.Respond(w, http.StatusCreated, RespCreateStack{
s.api.Respond(w, r, http.StatusCreated, RespCreateStack{
ID: stack.ID.String(),
OrgID: stack.OrgID.String(),
Name: stack.Name,
@ -209,13 +209,13 @@ func (s *HTTPServer) createStack(w http.ResponseWriter, r *http.Request) {
func (s *HTTPServer) deleteStack(w http.ResponseWriter, r *http.Request) {
orgID, err := getRequiredOrgIDFromQuery(r.URL.Query())
if err != nil {
s.api.Err(w, err)
s.api.Err(w, r, err)
return
}
stackID, err := influxdb.IDFromString(chi.URLParam(r, "stack_id"))
if err != nil {
s.api.Err(w, &influxdb.Error{
s.api.Err(w, r, &influxdb.Error{
Code: influxdb.EInvalid,
Msg: "the stack id provided in the path was invalid",
Err: err,
@ -225,7 +225,7 @@ func (s *HTTPServer) deleteStack(w http.ResponseWriter, r *http.Request) {
auth, err := pctx.GetAuthorizer(r.Context())
if err != nil {
s.api.Err(w, err)
s.api.Err(w, r, err)
return
}
userID := auth.GetUserID()
@ -236,11 +236,11 @@ func (s *HTTPServer) deleteStack(w http.ResponseWriter, r *http.Request) {
StackID: *stackID,
})
if err != nil {
s.api.Err(w, err)
s.api.Err(w, r, err)
return
}
s.api.Respond(w, http.StatusNoContent, nil)
s.api.Respond(w, r, http.StatusNoContent, nil)
}
func getRequiredOrgIDFromQuery(q url.Values) (influxdb.ID, error) {
@ -306,7 +306,7 @@ func (s *HTTPServer) createPkg(w http.ResponseWriter, r *http.Request) {
var reqBody ReqCreatePkg
if err := s.api.DecodeJSON(r.Body, &reqBody); err != nil {
s.api.Err(w, err)
s.api.Err(w, r, err)
return
}
defer r.Body.Close()
@ -328,7 +328,7 @@ func (s *HTTPServer) createPkg(w http.ResponseWriter, r *http.Request) {
newPkg, err := s.svc.CreatePkg(r.Context(), opts...)
if err != nil {
s.api.Err(w, err)
s.api.Err(w, r, err)
return
}
@ -347,7 +347,7 @@ func (s *HTTPServer) createPkg(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
}
s.encResp(w, enc, http.StatusOK, resp)
s.encResp(w, r, enc, http.StatusOK, resp)
}
// PkgRemote provides a package via a remote (i.e. a gist). If content type is not
@ -432,13 +432,13 @@ func (s *HTTPServer) applyPkg(w http.ResponseWriter, r *http.Request) {
var reqBody ReqApplyPkg
encoding, err := decodeWithEncoding(r, &reqBody)
if err != nil {
s.api.Err(w, newDecodeErr(encoding.String(), err))
s.api.Err(w, r, newDecodeErr(encoding.String(), err))
return
}
orgID, err := influxdb.IDFromString(reqBody.OrgID)
if err != nil {
s.api.Err(w, &influxdb.Error{
s.api.Err(w, r, &influxdb.Error{
Code: influxdb.EInvalid,
Msg: fmt.Sprintf("invalid organization ID provided: %q", reqBody.OrgID),
})
@ -448,7 +448,7 @@ func (s *HTTPServer) applyPkg(w http.ResponseWriter, r *http.Request) {
var stackID influxdb.ID
if reqBody.StackID != nil {
if err := stackID.DecodeFromString(*reqBody.StackID); err != nil {
s.api.Err(w, &influxdb.Error{
s.api.Err(w, r, &influxdb.Error{
Code: influxdb.EInvalid,
Msg: fmt.Sprintf("invalid stack ID provided: %q", *reqBody.StackID),
})
@ -458,14 +458,14 @@ func (s *HTTPServer) applyPkg(w http.ResponseWriter, r *http.Request) {
auth, err := pctx.GetAuthorizer(r.Context())
if err != nil {
s.api.Err(w, err)
s.api.Err(w, r, err)
return
}
userID := auth.GetUserID()
parsedPkg, err := reqBody.Pkgs(encoding)
if err != nil {
s.api.Err(w, &influxdb.Error{
s.api.Err(w, r, &influxdb.Error{
Code: influxdb.EUnprocessableEntity,
Err: err,
})
@ -480,7 +480,7 @@ func (s *HTTPServer) applyPkg(w http.ResponseWriter, r *http.Request) {
if reqBody.DryRun {
sum, diff, err := s.svc.DryRun(r.Context(), *orgID, userID, parsedPkg, applyOpts...)
if IsParseErr(err) {
s.api.Respond(w, http.StatusUnprocessableEntity, RespApplyPkg{
s.api.Respond(w, r, http.StatusUnprocessableEntity, RespApplyPkg{
Diff: diff,
Summary: sum,
Errors: convertParseErr(err),
@ -488,11 +488,11 @@ func (s *HTTPServer) applyPkg(w http.ResponseWriter, r *http.Request) {
return
}
if err != nil {
s.api.Err(w, err)
s.api.Err(w, r, err)
return
}
s.api.Respond(w, http.StatusOK, RespApplyPkg{
s.api.Respond(w, r, http.StatusOK, RespApplyPkg{
Diff: diff,
Summary: sum,
})
@ -503,11 +503,11 @@ func (s *HTTPServer) applyPkg(w http.ResponseWriter, r *http.Request) {
sum, diff, err := s.svc.Apply(r.Context(), *orgID, userID, parsedPkg, applyOpts...)
if err != nil && !IsParseErr(err) {
s.api.Err(w, err)
s.api.Err(w, r, err)
return
}
s.api.Respond(w, http.StatusCreated, RespApplyPkg{
s.api.Respond(w, r, http.StatusCreated, RespApplyPkg{
Diff: diff,
Summary: sum,
Errors: convertParseErr(err),
@ -551,10 +551,10 @@ func newJSONEnc(w io.Writer) encoder {
return enc
}
func (s *HTTPServer) encResp(w http.ResponseWriter, enc encoder, code int, res interface{}) {
func (s *HTTPServer) encResp(w http.ResponseWriter, r *http.Request, enc encoder, code int, res interface{}) {
w.WriteHeader(code)
if err := enc.Encode(res); err != nil {
s.api.Err(w, &influxdb.Error{
s.api.Err(w, r, &influxdb.Error{
Msg: fmt.Sprintf("unable to marshal; Err: %v", err),
Code: influxdb.EInternal,
Err: err,

View File

@ -81,7 +81,7 @@ func (h *SessionHandler) handleSignin(w http.ResponseWriter, r *http.Request) {
req, decErr := decodeSigninRequest(ctx, r)
if decErr != nil {
h.api.Err(w, ErrUnauthorized)
h.api.Err(w, r, ErrUnauthorized)
return
}
@ -89,18 +89,18 @@ func (h *SessionHandler) handleSignin(w http.ResponseWriter, r *http.Request) {
Name: &req.Username,
})
if err != nil {
h.api.Err(w, ErrUnauthorized)
h.api.Err(w, r, ErrUnauthorized)
return
}
if err := h.passSvc.ComparePassword(ctx, u.ID, req.Password); err != nil {
h.api.Err(w, ErrUnauthorized)
h.api.Err(w, r, ErrUnauthorized)
return
}
s, e := h.sessionSvc.CreateSession(ctx, req.Username)
if e != nil {
h.api.Err(w, ErrUnauthorized)
h.api.Err(w, r, ErrUnauthorized)
return
}
@ -134,12 +134,12 @@ func (h *SessionHandler) handleSignout(w http.ResponseWriter, r *http.Request) {
req, err := decodeSignoutRequest(ctx, r)
if err != nil {
h.api.Err(w, ErrUnauthorized)
h.api.Err(w, r, ErrUnauthorized)
return
}
if err := h.sessionSvc.ExpireSession(ctx, req.Key); err != nil {
h.api.Err(w, ErrUnauthorized)
h.api.Err(w, r, ErrUnauthorized)
return
}

View File

@ -48,7 +48,7 @@ func (h *urmHandler) getURMsByType(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
req, err := h.decodeGetRequest(ctx, r)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
@ -59,7 +59,7 @@ func (h *urmHandler) getURMsByType(w http.ResponseWriter, r *http.Request) {
}
mappings, _, err := h.svc.FindUserResourceMappings(ctx, filter)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
@ -70,7 +70,7 @@ func (h *urmHandler) getURMsByType(w http.ResponseWriter, r *http.Request) {
}
user, err := h.userSvc.FindUserByID(ctx, m.UserID)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
@ -78,7 +78,7 @@ func (h *urmHandler) getURMsByType(w http.ResponseWriter, r *http.Request) {
}
h.log.Debug("Members/owners retrieved", zap.String("users", fmt.Sprint(users)))
h.api.Respond(w, http.StatusOK, newResourceUsersResponse(filter, users))
h.api.Respond(w, r, http.StatusOK, newResourceUsersResponse(filter, users))
}
@ -112,13 +112,13 @@ func (h *urmHandler) postURMByType(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
req, err := h.decodePostRequest(ctx, r)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
user, err := h.userSvc.FindUserByID(ctx, req.UserID)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
@ -129,12 +129,12 @@ func (h *urmHandler) postURMByType(w http.ResponseWriter, r *http.Request) {
UserType: userType,
}
if err := h.svc.CreateUserResourceMapping(ctx, mapping); err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
h.log.Debug("Member/owner created", zap.String("mapping", fmt.Sprint(mapping)))
h.api.Respond(w, http.StatusCreated, newResourceUserResponse(user, userType))
h.api.Respond(w, r, http.StatusCreated, newResourceUserResponse(user, userType))
}
type postRequest struct {
@ -178,12 +178,12 @@ func (h *urmHandler) deleteURM(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
req, err := h.decodeDeleteRequest(ctx, r)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
if err := h.svc.DeleteUserResourceMapping(ctx, req.resourceID, req.userID); err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
h.log.Debug("Member deleted", zap.String("resourceID", req.resourceID.String()), zap.String("memberID", req.userID.String()))

View File

@ -20,7 +20,7 @@ func ValidResource(api *kit.API, lookupOrgByResourceID func(context.Context, inf
statusW := kit.NewStatusResponseWriter(w)
id, err := influxdb.IDFromString(chi.URLParam(r, "id"))
if err != nil {
api.Err(w, ErrCorruptID(err))
api.Err(w, r, ErrCorruptID(err))
return
}
@ -28,7 +28,7 @@ func ValidResource(api *kit.API, lookupOrgByResourceID func(context.Context, inf
orgID, err := lookupOrgByResourceID(ctx, *id)
if err != nil {
api.Err(w, err)
api.Err(w, r, err)
return
}

View File

@ -250,28 +250,28 @@ func newBucketsResponse(ctx context.Context, opts influxdb.FindOptions, f influx
func (h *BucketHandler) handlePostBucket(w http.ResponseWriter, r *http.Request) {
var b postBucketRequest
if err := h.api.DecodeJSON(r.Body, &b); err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
if err := b.OK(); err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
bucket := b.toInfluxDB()
if err := validBucketName(bucket); err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
if err := h.bucketSvc.CreateBucket(r.Context(), bucket); err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
h.log.Debug("Bucket created", zap.String("bucket", fmt.Sprint(bucket)))
h.api.Respond(w, http.StatusCreated, NewBucketResponse(bucket))
h.api.Respond(w, r, http.StatusCreated, NewBucketResponse(bucket))
}
type postBucketRequest struct {
@ -334,55 +334,55 @@ func (h *BucketHandler) handleGetBucket(w http.ResponseWriter, r *http.Request)
id, err := influxdb.IDFromString(chi.URLParam(r, "id"))
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
b, err := h.bucketSvc.FindBucketByID(ctx, *id)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
h.log.Debug("Bucket retrieved", zap.String("bucket", fmt.Sprint(b)))
h.api.Respond(w, http.StatusOK, NewBucketResponse(b))
h.api.Respond(w, r, http.StatusOK, NewBucketResponse(b))
}
// handleDeleteBucket is the HTTP handler for the DELETE /api/v2/buckets/:id route.
func (h *BucketHandler) handleDeleteBucket(w http.ResponseWriter, r *http.Request) {
id, err := influxdb.IDFromString(chi.URLParam(r, "id"))
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
if err := h.bucketSvc.DeleteBucket(r.Context(), *id); err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
h.log.Debug("Bucket deleted", zap.String("bucketID", id.String()))
h.api.Respond(w, http.StatusNoContent, nil)
h.api.Respond(w, r, http.StatusNoContent, nil)
}
// handleGetBuckets is the HTTP handler for the GET /api/v2/buckets route.
func (h *BucketHandler) handleGetBuckets(w http.ResponseWriter, r *http.Request) {
bucketsRequest, err := decodeGetBucketsRequest(r)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
bs, _, err := h.bucketSvc.FindBuckets(r.Context(), bucketsRequest.filter, bucketsRequest.opts)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
h.log.Debug("Buckets retrieved", zap.String("buckets", fmt.Sprint(bs)))
h.api.Respond(w, http.StatusOK, newBucketsResponse(r.Context(), bucketsRequest.opts, bucketsRequest.filter, bs))
h.api.Respond(w, r, http.StatusOK, newBucketsResponse(r.Context(), bucketsRequest.opts, bucketsRequest.filter, bs))
}
type getBucketsRequest struct {
@ -432,38 +432,38 @@ func decodeGetBucketsRequest(r *http.Request) (*getBucketsRequest, error) {
func (h *BucketHandler) handlePatchBucket(w http.ResponseWriter, r *http.Request) {
id, err := influxdb.IDFromString(chi.URLParam(r, "id"))
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
var reqBody bucketUpdate
if err := h.api.DecodeJSON(r.Body, &reqBody); err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
if reqBody.Name != nil {
b, err := h.bucketSvc.FindBucketByID(r.Context(), *id)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
b.Name = *reqBody.Name
if err := validBucketName(b); err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
}
b, err := h.bucketSvc.UpdateBucket(r.Context(), *id, *reqBody.toInfluxDB())
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
h.log.Debug("Bucket updated", zap.String("bucket", fmt.Sprint(b)))
h.api.Respond(w, http.StatusOK, NewBucketResponse(b))
h.api.Respond(w, r, http.StatusOK, NewBucketResponse(b))
}
func (h *BucketHandler) lookupOrgByBucketID(ctx context.Context, id influxdb.ID) (influxdb.ID, error) {

View File

@ -65,12 +65,12 @@ func (h *OnboardHandler) handleIsOnboarding(w http.ResponseWriter, r *http.Reque
ctx := r.Context()
result, err := h.onboardingSvc.IsOnboarding(ctx)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
h.log.Debug("Onboarding eligibility check finished", zap.String("result", fmt.Sprint(result)))
h.api.Respond(w, http.StatusOK, isOnboardingResponse{result})
h.api.Respond(w, r, http.StatusOK, isOnboardingResponse{result})
}
// handleInitialOnboardRequest is the HTTP handler for the GET /api/v2/setup route.
@ -78,17 +78,17 @@ func (h *OnboardHandler) handleInitialOnboardRequest(w http.ResponseWriter, r *h
ctx := r.Context()
req, err := decodeOnboardRequest(ctx, r)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
results, err := h.onboardingSvc.OnboardInitialUser(ctx, req)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
h.log.Debug("Onboarding setup completed", zap.String("results", fmt.Sprint(results)))
h.api.Respond(w, http.StatusCreated, NewOnboardingResponse(results))
h.api.Respond(w, r, http.StatusCreated, NewOnboardingResponse(results))
}
// isOnboarding is the HTTP handler for the POST /api/v2/setup route.
@ -96,17 +96,17 @@ func (h *OnboardHandler) handleOnboardRequest(w http.ResponseWriter, r *http.Req
ctx := r.Context()
req, err := decodeOnboardRequest(ctx, r)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
results, err := h.onboardingSvc.OnboardUser(ctx, req)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
h.log.Debug("Onboarding setup completed", zap.String("results", fmt.Sprint(results)))
h.api.Respond(w, http.StatusCreated, NewOnboardingResponse(results))
h.api.Respond(w, r, http.StatusCreated, NewOnboardingResponse(results))
}
type onboardingResponse struct {

View File

@ -95,36 +95,36 @@ func newOrgsResponse(orgs []*influxdb.Organization) *orgsResponse {
func (h *OrgHandler) handlePostOrg(w http.ResponseWriter, r *http.Request) {
var org influxdb.Organization
if err := h.api.DecodeJSON(r.Body, &org); err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
if err := h.orgSvc.CreateOrganization(r.Context(), &org); err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
h.log.Debug("Org created", zap.String("org", fmt.Sprint(org)))
h.api.Respond(w, http.StatusCreated, newOrgResponse(org))
h.api.Respond(w, r, http.StatusCreated, newOrgResponse(org))
}
// handleGetOrg is the HTTP handler for the GET /api/v2/orgs/:id route.
func (h *OrgHandler) handleGetOrg(w http.ResponseWriter, r *http.Request) {
id, err := influxdb.IDFromString(chi.URLParam(r, "id"))
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
org, err := h.orgSvc.FindOrganizationByID(r.Context(), *id)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
h.log.Debug("Org retrieved", zap.String("org", fmt.Sprint(org)))
h.api.Respond(w, http.StatusOK, newOrgResponse(*org))
h.api.Respond(w, r, http.StatusOK, newOrgResponse(*org))
}
// handleGetOrgs is the HTTP handler for the GET /api/v2/orgs route.
@ -151,54 +151,54 @@ func (h *OrgHandler) handleGetOrgs(w http.ResponseWriter, r *http.Request) {
orgs, _, err := h.orgSvc.FindOrganizations(r.Context(), filter)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
h.log.Debug("Orgs retrieved", zap.String("org", fmt.Sprint(orgs)))
h.api.Respond(w, http.StatusOK, newOrgsResponse(orgs))
h.api.Respond(w, r, http.StatusOK, newOrgsResponse(orgs))
}
// handlePatchOrg is the HTTP handler for the PATH /api/v2/orgs route.
func (h *OrgHandler) handlePatchOrg(w http.ResponseWriter, r *http.Request) {
id, err := influxdb.IDFromString(chi.URLParam(r, "id"))
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
var upd influxdb.OrganizationUpdate
if err := h.api.DecodeJSON(r.Body, &upd); err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
org, err := h.orgSvc.UpdateOrganization(r.Context(), *id, upd)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
h.log.Debug("Org updated", zap.String("org", fmt.Sprint(org)))
h.api.Respond(w, http.StatusOK, newOrgResponse(*org))
h.api.Respond(w, r, http.StatusOK, newOrgResponse(*org))
}
// handleDeleteOrganization is the HTTP handler for the DELETE /api/v2/orgs/:id route.
func (h *OrgHandler) handleDeleteOrg(w http.ResponseWriter, r *http.Request) {
id, err := influxdb.IDFromString(chi.URLParam(r, "id"))
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
ctx := r.Context()
if err := h.orgSvc.DeleteOrganization(ctx, *id); err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
h.log.Debug("Org deleted", zap.String("orgID", fmt.Sprint(id)))
h.api.Respond(w, http.StatusNoContent, nil)
h.api.Respond(w, r, http.StatusNoContent, nil)
}
func (h *OrgHandler) lookupOrgByID(ctx context.Context, id influxdb.ID) (influxdb.ID, error) {

View File

@ -86,7 +86,7 @@ func (h *UserHandler) handlePostUserPassword(w http.ResponseWriter, r *http.Requ
var body passwordSetRequest
err := json.NewDecoder(r.Body).Decode(&body)
if err != nil {
h.api.Err(w, &influxdb.Error{
h.api.Err(w, r, &influxdb.Error{
Code: influxdb.EInvalid,
Err: err,
})
@ -96,7 +96,7 @@ func (h *UserHandler) handlePostUserPassword(w http.ResponseWriter, r *http.Requ
param := chi.URLParam(r, "id")
userID, err := influxdb.IDFromString(param)
if err != nil {
h.api.Err(w, &influxdb.Error{
h.api.Err(w, r, &influxdb.Error{
Msg: "invalid user ID provided in route",
})
return
@ -104,7 +104,7 @@ func (h *UserHandler) handlePostUserPassword(w http.ResponseWriter, r *http.Requ
err = h.passwordSvc.SetPassword(r.Context(), *userID, body.Password)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
@ -120,7 +120,7 @@ func (h *UserHandler) putPassword(ctx context.Context, w http.ResponseWriter, r
param := chi.URLParam(r, "id")
userID, err := influxdb.IDFromString(param)
if err != nil {
h.api.Err(w, &influxdb.Error{
h.api.Err(w, r, &influxdb.Error{
Msg: "invalid user ID provided in route",
})
return
@ -138,7 +138,7 @@ func (h *UserHandler) handlePutUserPassword(w http.ResponseWriter, r *http.Reque
ctx := r.Context()
_, err := h.putPassword(ctx, w, r)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
h.log.Debug("User password updated")
@ -182,7 +182,7 @@ func (h *UserHandler) handlePostUser(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
req, err := decodePostUserRequest(ctx, r)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
@ -191,12 +191,12 @@ func (h *UserHandler) handlePostUser(w http.ResponseWriter, r *http.Request) {
}
if err := h.userSvc.CreateUser(ctx, req.User); err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
h.log.Debug("User created", zap.String("user", fmt.Sprint(req.User)))
h.api.Respond(w, http.StatusCreated, newUserResponse(req.User))
h.api.Respond(w, r, http.StatusCreated, newUserResponse(req.User))
}
type postUserRequest struct {
@ -220,7 +220,7 @@ func (h *UserHandler) handleGetMe(w http.ResponseWriter, r *http.Request) {
a, err := icontext.GetAuthorizer(ctx)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
@ -228,11 +228,11 @@ func (h *UserHandler) handleGetMe(w http.ResponseWriter, r *http.Request) {
user, err := h.userSvc.FindUserByID(ctx, id)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
h.api.Respond(w, http.StatusOK, newUserResponse(user))
h.api.Respond(w, r, http.StatusOK, newUserResponse(user))
}
// handleGetUser is the HTTP handler for the GET /api/v2/users/:id route.
@ -240,18 +240,18 @@ func (h *UserHandler) handleGetUser(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
req, err := decodeGetUserRequest(ctx, r)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
b, err := h.userSvc.FindUserByID(ctx, req.UserID)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
h.log.Debug("User retrieved", zap.String("user", fmt.Sprint(b)))
h.api.Respond(w, http.StatusOK, newUserResponse(b))
h.api.Respond(w, r, http.StatusOK, newUserResponse(b))
}
type getUserRequest struct {
@ -284,12 +284,12 @@ func (h *UserHandler) handleDeleteUser(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
req, err := decodeDeleteUserRequest(ctx, r)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
if err := h.userSvc.DeleteUser(ctx, req.UserID); err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
h.log.Debug("User deleted", zap.String("userID", fmt.Sprint(req.UserID)))
@ -373,18 +373,18 @@ func (h *UserHandler) handleGetUsers(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
req, err := decodeGetUsersRequest(ctx, r)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
users, _, err := h.userSvc.FindUsers(ctx, req.filter)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
h.log.Debug("Users retrieved", zap.String("users", fmt.Sprint(users)))
h.api.Respond(w, http.StatusOK, newUsersResponse(users))
h.api.Respond(w, r, http.StatusOK, newUsersResponse(users))
}
type getUsersRequest struct {
@ -415,18 +415,18 @@ func (h *UserHandler) handlePatchUser(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
req, err := decodePatchUserRequest(ctx, r)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
b, err := h.userSvc.UpdateUser(ctx, req.UserID, req.Update)
if err != nil {
h.api.Err(w, err)
h.api.Err(w, r, err)
return
}
h.log.Debug("Users updated", zap.String("user", fmt.Sprint(b)))
h.api.Respond(w, http.StatusOK, newUserResponse(b))
h.api.Respond(w, r, http.StatusOK, newUserResponse(b))
}
type patchUserRequest struct {