232 lines
5.8 KiB
Go
232 lines
5.8 KiB
Go
package tenant
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"github.com/go-chi/chi"
|
|
"github.com/go-chi/chi/middleware"
|
|
"github.com/influxdata/influxdb/v2"
|
|
"github.com/influxdata/influxdb/v2/kit/platform"
|
|
kithttp "github.com/influxdata/influxdb/v2/kit/transport/http"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// OrgHandler represents an HTTP API handler for organizations.
|
|
type OrgHandler struct {
|
|
chi.Router
|
|
api *kithttp.API
|
|
log *zap.Logger
|
|
orgSvc influxdb.OrganizationService
|
|
}
|
|
|
|
const (
|
|
prefixOrganizations = "/api/v2/orgs"
|
|
)
|
|
|
|
func (h *OrgHandler) Prefix() string {
|
|
return prefixOrganizations
|
|
}
|
|
|
|
// NewHTTPOrgHandler constructs a new http server.
|
|
func NewHTTPOrgHandler(log *zap.Logger, orgService influxdb.OrganizationService, urm http.Handler, secretHandler http.Handler) *OrgHandler {
|
|
svr := &OrgHandler{
|
|
api: kithttp.NewAPI(kithttp.WithLog(log)),
|
|
log: log,
|
|
orgSvc: orgService,
|
|
}
|
|
|
|
r := chi.NewRouter()
|
|
r.Use(
|
|
middleware.Recoverer,
|
|
middleware.RequestID,
|
|
middleware.RealIP,
|
|
)
|
|
|
|
r.Route("/", func(r chi.Router) {
|
|
r.Post("/", svr.handlePostOrg)
|
|
r.Get("/", svr.handleGetOrgs)
|
|
|
|
r.Route("/{id}", func(r chi.Router) {
|
|
r.Get("/", svr.handleGetOrg)
|
|
r.Patch("/", svr.handlePatchOrg)
|
|
r.Delete("/", svr.handleDeleteOrg)
|
|
|
|
// mount embedded resources
|
|
mountableRouter := r.With(kithttp.ValidResource(svr.api, svr.lookupOrgByID))
|
|
mountableRouter.Mount("/members", urm)
|
|
mountableRouter.Mount("/owners", urm)
|
|
mountableRouter.Mount("/secrets", secretHandler)
|
|
})
|
|
})
|
|
svr.Router = r
|
|
return svr
|
|
}
|
|
|
|
type orgResponse struct {
|
|
Links map[string]string `json:"links"`
|
|
influxdb.Organization
|
|
}
|
|
|
|
func newOrgResponse(o influxdb.Organization) orgResponse {
|
|
return orgResponse{
|
|
Links: map[string]string{
|
|
"self": fmt.Sprintf("/api/v2/orgs/%s", o.ID),
|
|
"logs": fmt.Sprintf("/api/v2/orgs/%s/logs", o.ID),
|
|
"members": fmt.Sprintf("/api/v2/orgs/%s/members", o.ID),
|
|
"owners": fmt.Sprintf("/api/v2/orgs/%s/owners", o.ID),
|
|
"secrets": fmt.Sprintf("/api/v2/orgs/%s/secrets", o.ID),
|
|
"labels": fmt.Sprintf("/api/v2/orgs/%s/labels", o.ID),
|
|
"buckets": fmt.Sprintf("/api/v2/buckets?org=%s", o.Name),
|
|
"tasks": fmt.Sprintf("/api/v2/tasks?org=%s", o.Name),
|
|
"dashboards": fmt.Sprintf("/api/v2/dashboards?org=%s", o.Name),
|
|
},
|
|
Organization: o,
|
|
}
|
|
}
|
|
|
|
type orgsResponse struct {
|
|
Links map[string]string `json:"links"`
|
|
Organizations []orgResponse `json:"orgs"`
|
|
}
|
|
|
|
func newOrgsResponse(orgs []*influxdb.Organization) *orgsResponse {
|
|
res := orgsResponse{
|
|
Links: map[string]string{
|
|
"self": "/api/v2/orgs",
|
|
},
|
|
Organizations: []orgResponse{},
|
|
}
|
|
for _, org := range orgs {
|
|
res.Organizations = append(res.Organizations, newOrgResponse(*org))
|
|
}
|
|
return &res
|
|
}
|
|
|
|
// handlePostOrg is the HTTP handler for the POST /api/v2/orgs route.
|
|
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, r, err)
|
|
return
|
|
}
|
|
|
|
if err := h.orgSvc.CreateOrganization(r.Context(), &org); err != nil {
|
|
h.api.Err(w, r, err)
|
|
return
|
|
}
|
|
|
|
h.log.Debug("Org created", zap.String("org", fmt.Sprint(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 := platform.IDFromString(chi.URLParam(r, "id"))
|
|
if err != nil {
|
|
h.api.Err(w, r, err)
|
|
return
|
|
}
|
|
|
|
org, err := h.orgSvc.FindOrganizationByID(r.Context(), *id)
|
|
if err != nil {
|
|
h.api.Err(w, r, err)
|
|
return
|
|
}
|
|
h.log.Debug("Org retrieved", zap.String("org", fmt.Sprint(org)))
|
|
|
|
h.api.Respond(w, r, http.StatusOK, newOrgResponse(*org))
|
|
}
|
|
|
|
// handleGetOrgs is the HTTP handler for the GET /api/v2/orgs route.
|
|
func (h *OrgHandler) handleGetOrgs(w http.ResponseWriter, r *http.Request) {
|
|
qp := r.URL.Query()
|
|
|
|
opts, err := influxdb.DecodeFindOptions(r)
|
|
if err != nil {
|
|
h.api.Err(w, r, err)
|
|
return
|
|
}
|
|
|
|
var filter influxdb.OrganizationFilter
|
|
if name := qp.Get("org"); name != "" {
|
|
filter.Name = &name
|
|
}
|
|
|
|
if id := qp.Get("orgID"); id != "" {
|
|
i, err := platform.IDFromString(id)
|
|
if err == nil {
|
|
filter.ID = i
|
|
}
|
|
}
|
|
|
|
if id := qp.Get("userID"); id != "" {
|
|
i, err := platform.IDFromString(id)
|
|
if err == nil {
|
|
filter.UserID = i
|
|
}
|
|
}
|
|
|
|
orgs, _, err := h.orgSvc.FindOrganizations(r.Context(), filter, *opts)
|
|
if err != nil {
|
|
h.api.Err(w, r, err)
|
|
return
|
|
}
|
|
h.log.Debug("Orgs retrieved", zap.String("org", fmt.Sprint(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 := platform.IDFromString(chi.URLParam(r, "id"))
|
|
if err != nil {
|
|
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, r, err)
|
|
return
|
|
}
|
|
|
|
org, err := h.orgSvc.UpdateOrganization(r.Context(), *id, upd)
|
|
if err != nil {
|
|
h.api.Err(w, r, err)
|
|
return
|
|
}
|
|
h.log.Debug("Org updated", zap.String("org", fmt.Sprint(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 := platform.IDFromString(chi.URLParam(r, "id"))
|
|
if err != nil {
|
|
h.api.Err(w, r, err)
|
|
return
|
|
}
|
|
|
|
ctx := r.Context()
|
|
if err := h.orgSvc.DeleteOrganization(ctx, *id); err != nil {
|
|
h.api.Err(w, r, err)
|
|
return
|
|
}
|
|
h.log.Debug("Org deleted", zap.String("orgID", fmt.Sprint(id)))
|
|
|
|
h.api.Respond(w, r, http.StatusNoContent, nil)
|
|
}
|
|
|
|
func (h *OrgHandler) lookupOrgByID(ctx context.Context, id platform.ID) (platform.ID, error) {
|
|
_, err := h.orgSvc.FindOrganizationByID(ctx, id)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
return id, nil
|
|
}
|