influxdb/http/api_handler.go

284 lines
12 KiB
Go

package http
import (
"net/http"
"github.com/go-chi/chi"
"github.com/influxdata/influxdb"
"github.com/influxdata/influxdb/authorizer"
"github.com/influxdata/influxdb/chronograf/server"
"github.com/influxdata/influxdb/http/metric"
"github.com/influxdata/influxdb/kit/prom"
kithttp "github.com/influxdata/influxdb/kit/transport/http"
"github.com/influxdata/influxdb/query"
"github.com/influxdata/influxdb/storage"
"github.com/prometheus/client_golang/prometheus"
"go.uber.org/zap"
)
// APIHandler is a collection of all the service handlers.
type APIHandler struct {
chi.Router
}
// APIBackend is all services and associated parameters required to construct
// an APIHandler.
type APIBackend struct {
AssetsPath string // if empty then assets are served from bindata.
Logger *zap.Logger
influxdb.HTTPErrorHandler
SessionRenewDisabled bool
// MaxBatchSizeBytes is the maximum number of bytes which can be written
// in a single points batch
MaxBatchSizeBytes int64
// WriteParserMaxBytes specifies the maximum number of bytes that may be allocated when processing a single
// write request. A value of zero specifies there is no limit.
WriteParserMaxBytes int
// WriteParserMaxLines specifies the maximum number of lines that may be parsed when processing a single
// write request. A value of zero specifies there is no limit.
WriteParserMaxLines int
// WriteParserMaxValues specifies the maximum number of values that may be parsed when processing a single
// write request. A value of zero specifies there is no limit.
WriteParserMaxValues int
NewBucketService func(*influxdb.Source) (influxdb.BucketService, error)
NewQueryService func(*influxdb.Source) (query.ProxyQueryService, error)
WriteEventRecorder metric.EventRecorder
QueryEventRecorder metric.EventRecorder
PointsWriter storage.PointsWriter
DeleteService influxdb.DeleteService
BackupService influxdb.BackupService
KVBackupService influxdb.KVBackupService
AuthorizationService influxdb.AuthorizationService
BucketService influxdb.BucketService
SessionService influxdb.SessionService
UserService influxdb.UserService
OrganizationService influxdb.OrganizationService
UserResourceMappingService influxdb.UserResourceMappingService
LabelService influxdb.LabelService
DashboardService influxdb.DashboardService
DashboardOperationLogService influxdb.DashboardOperationLogService
BucketOperationLogService influxdb.BucketOperationLogService
UserOperationLogService influxdb.UserOperationLogService
OrganizationOperationLogService influxdb.OrganizationOperationLogService
SourceService influxdb.SourceService
VariableService influxdb.VariableService
PasswordsService influxdb.PasswordsService
OnboardingService influxdb.OnboardingService
InfluxQLService query.ProxyQueryService
FluxService query.ProxyQueryService
TaskService influxdb.TaskService
CheckService influxdb.CheckService
TelegrafService influxdb.TelegrafConfigStore
ScraperTargetStoreService influxdb.ScraperTargetStoreService
SecretService influxdb.SecretService
LookupService influxdb.LookupService
ChronografService *server.Service
OrgLookupService authorizer.OrganizationService
DocumentService influxdb.DocumentService
NotificationRuleStore influxdb.NotificationRuleStore
NotificationEndpointService influxdb.NotificationEndpointService
}
// PrometheusCollectors exposes the prometheus collectors associated with an APIBackend.
func (b *APIBackend) PrometheusCollectors() []prometheus.Collector {
var cs []prometheus.Collector
if pc, ok := b.WriteEventRecorder.(prom.PrometheusCollector); ok {
cs = append(cs, pc.PrometheusCollectors()...)
}
if pc, ok := b.QueryEventRecorder.(prom.PrometheusCollector); ok {
cs = append(cs, pc.PrometheusCollectors()...)
}
return cs
}
// APIHandlerOptFn is a functional input param to set parameters on
// the APIHandler.
type APIHandlerOptFn func(chi.Router)
// WithResourceHandler registers a resource handler on the APIHandler.
func WithResourceHandler(resHandler kithttp.ResourceHandler) APIHandlerOptFn {
return func(h chi.Router) {
h.Mount(resHandler.Prefix(), resHandler)
}
}
// NewAPIHandler constructs all api handlers beneath it and returns an APIHandler
func NewAPIHandler(b *APIBackend, opts ...APIHandlerOptFn) *APIHandler {
h := &APIHandler{
Router: newBaseChiRouter(b.HTTPErrorHandler),
}
noAuthUserResourceMappingService := b.UserResourceMappingService
b.UserResourceMappingService = authorizer.NewURMService(b.OrgLookupService, b.UserResourceMappingService)
b.LabelService = authorizer.NewLabelServiceWithOrg(b.LabelService, b.OrgLookupService)
h.Mount("/api/v2", serveLinksHandler(b.HTTPErrorHandler))
authorizationBackend := NewAuthorizationBackend(b.Logger.With(zap.String("handler", "authorization")), b)
authorizationBackend.AuthorizationService = authorizer.NewAuthorizationService(b.AuthorizationService)
h.Mount(prefixAuthorization, NewAuthorizationHandler(b.Logger, authorizationBackend))
bucketBackend := NewBucketBackend(b.Logger.With(zap.String("handler", "bucket")), b)
bucketBackend.BucketService = authorizer.NewBucketService(b.BucketService, noAuthUserResourceMappingService)
h.Mount(prefixBuckets, NewBucketHandler(b.Logger, bucketBackend))
checkBackend := NewCheckBackend(b.Logger.With(zap.String("handler", "check")), b)
checkBackend.CheckService = authorizer.NewCheckService(b.CheckService,
b.UserResourceMappingService, b.OrganizationService)
h.Mount(prefixChecks, NewCheckHandler(b.Logger, checkBackend))
h.Mount(prefixChronograf, NewChronografHandler(b.ChronografService, b.HTTPErrorHandler))
dashboardBackend := NewDashboardBackend(b.Logger.With(zap.String("handler", "dashboard")), b)
dashboardBackend.DashboardService = authorizer.NewDashboardService(b.DashboardService)
h.Mount(prefixDashboards, NewDashboardHandler(b.Logger, dashboardBackend))
deleteBackend := NewDeleteBackend(b.Logger.With(zap.String("handler", "delete")), b)
h.Mount(prefixDelete, NewDeleteHandler(b.Logger, deleteBackend))
documentBackend := NewDocumentBackend(b.Logger.With(zap.String("handler", "document")), b)
documentBackend.DocumentService = authorizer.NewDocumentService(b.DocumentService)
h.Mount(prefixDocuments, NewDocumentHandler(documentBackend))
fluxBackend := NewFluxBackend(b.Logger.With(zap.String("handler", "query")), b)
h.Mount(prefixQuery, NewFluxHandler(b.Logger, fluxBackend))
h.Mount(prefixLabels, NewLabelHandler(b.Logger, b.LabelService, b.HTTPErrorHandler))
notificationEndpointBackend := NewNotificationEndpointBackend(b.Logger.With(zap.String("handler", "notificationEndpoint")), b)
notificationEndpointBackend.NotificationEndpointService = authorizer.NewNotificationEndpointService(b.NotificationEndpointService,
b.UserResourceMappingService, b.OrganizationService)
h.Mount(prefixNotificationEndpoints, NewNotificationEndpointHandler(notificationEndpointBackend.Logger(), notificationEndpointBackend))
notificationRuleBackend := NewNotificationRuleBackend(b.Logger.With(zap.String("handler", "notification_rule")), b)
notificationRuleBackend.NotificationRuleStore = authorizer.NewNotificationRuleStore(b.NotificationRuleStore,
b.UserResourceMappingService, b.OrganizationService)
h.Mount(prefixNotificationRules, NewNotificationRuleHandler(b.Logger, notificationRuleBackend))
orgBackend := NewOrgBackend(b.Logger.With(zap.String("handler", "org")), b)
orgBackend.OrganizationService = authorizer.NewOrgService(b.OrganizationService)
orgBackend.SecretService = authorizer.NewSecretService(b.SecretService)
h.Mount(prefixOrganizations, NewOrgHandler(b.Logger, orgBackend))
scraperBackend := NewScraperBackend(b.Logger.With(zap.String("handler", "scraper")), b)
scraperBackend.ScraperStorageService = authorizer.NewScraperTargetStoreService(b.ScraperTargetStoreService,
b.UserResourceMappingService,
b.OrganizationService)
h.Mount(prefixTargets, NewScraperHandler(b.Logger, scraperBackend))
sessionBackend := newSessionBackend(b.Logger.With(zap.String("handler", "session")), b)
sessionHandler := NewSessionHandler(b.Logger, sessionBackend)
h.Mount(prefixSignIn, sessionHandler)
h.Mount(prefixSignOut, sessionHandler)
setupBackend := NewSetupBackend(b.Logger.With(zap.String("handler", "setup")), b)
h.Mount(prefixSetup, NewSetupHandler(b.Logger, setupBackend))
sourceBackend := NewSourceBackend(b.Logger.With(zap.String("handler", "source")), b)
sourceBackend.SourceService = authorizer.NewSourceService(b.SourceService)
sourceBackend.BucketService = authorizer.NewBucketService(b.BucketService, noAuthUserResourceMappingService)
h.Mount(prefixSources, NewSourceHandler(b.Logger, sourceBackend))
h.Mount("/api/v2/swagger.json", newSwaggerLoader(b.Logger.With(zap.String("service", "swagger-loader")), b.HTTPErrorHandler))
taskLogger := b.Logger.With(zap.String("handler", "bucket"))
taskBackend := NewTaskBackend(taskLogger, b)
taskBackend.TaskService = authorizer.NewTaskService(taskLogger, b.TaskService)
taskHandler := NewTaskHandler(b.Logger, taskBackend)
h.Mount(prefixTasks, taskHandler)
telegrafBackend := NewTelegrafBackend(b.Logger.With(zap.String("handler", "telegraf")), b)
telegrafBackend.TelegrafService = authorizer.NewTelegrafConfigService(b.TelegrafService, b.UserResourceMappingService)
h.Mount(prefixTelegrafPlugins, NewTelegrafHandler(b.Logger, telegrafBackend))
h.Mount(prefixTelegraf, NewTelegrafHandler(b.Logger, telegrafBackend))
userBackend := NewUserBackend(b.Logger.With(zap.String("handler", "user")), b)
userBackend.UserService = authorizer.NewUserService(b.UserService)
userBackend.PasswordsService = authorizer.NewPasswordService(b.PasswordsService)
userHandler := NewUserHandler(b.Logger, userBackend)
h.Mount(prefixMe, userHandler)
h.Mount(prefixUsers, userHandler)
variableBackend := NewVariableBackend(b.Logger.With(zap.String("handler", "variable")), b)
variableBackend.VariableService = authorizer.NewVariableService(b.VariableService)
h.Mount(prefixVariables, NewVariableHandler(b.Logger, variableBackend))
backupBackend := NewBackupBackend(b)
backupBackend.BackupService = authorizer.NewBackupService(backupBackend.BackupService)
h.Mount(prefixBackup, NewBackupHandler(backupBackend))
writeBackend := NewWriteBackend(b.Logger.With(zap.String("handler", "write")), b)
h.Mount(prefixWrite, NewWriteHandler(b.Logger, writeBackend,
WithMaxBatchSizeBytes(b.MaxBatchSizeBytes),
WithParserMaxBytes(b.WriteParserMaxBytes),
WithParserMaxLines(b.WriteParserMaxLines),
WithParserMaxValues(b.WriteParserMaxValues),
))
for _, o := range opts {
o(h)
}
return h
}
var apiLinks = map[string]interface{}{
// when adding new links, please take care to keep this list alphabetical
// as this makes it easier to verify values against the swagger document.
"authorizations": "/api/v2/authorizations",
"backup": "/api/v2/backup",
"buckets": "/api/v2/buckets",
"dashboards": "/api/v2/dashboards",
"external": map[string]string{
"statusFeed": "https://www.influxdata.com/feed/json",
},
"labels": "/api/v2/labels",
"variables": "/api/v2/variables",
"me": "/api/v2/me",
"notificationRules": "/api/v2/notificationRules",
"notificationEndpoints": "/api/v2/notificationEndpoints",
"orgs": "/api/v2/orgs",
"query": map[string]string{
"self": "/api/v2/query",
"ast": "/api/v2/query/ast",
"analyze": "/api/v2/query/analyze",
"suggestions": "/api/v2/query/suggestions",
},
"setup": "/api/v2/setup",
"signin": "/api/v2/signin",
"signout": "/api/v2/signout",
"sources": "/api/v2/sources",
"scrapers": "/api/v2/scrapers",
"swagger": "/api/v2/swagger.json",
"system": map[string]string{
"metrics": "/metrics",
"debug": "/debug/pprof",
"health": "/health",
},
"tasks": "/api/v2/tasks",
"checks": "/api/v2/checks",
"telegrafs": "/api/v2/telegrafs",
"plugins": "/api/v2/telegraf/plugins",
"users": "/api/v2/users",
"write": "/api/v2/write",
"delete": "/api/v2/delete",
}
func serveLinksHandler(errorHandler influxdb.HTTPErrorHandler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
if err := encodeResponse(ctx, w, http.StatusOK, apiLinks); err != nil {
errorHandler.HandleHTTPError(ctx, err, w)
}
}
return http.HandlerFunc(fn)
}